cpu/x86/smm: Support PARALLEL_MP with SMM_ASEG

This will allow to migrate all platform to the parallel_mp init code
and drop the old lapic_init code.

Change-Id: If499e21a8dc7fca18bd5990f833170d0fc21e10c
Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
Signed-off-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/58700
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
diff --git a/src/cpu/x86/Kconfig b/src/cpu/x86/Kconfig
index 86f31e0..d5c688d 100644
--- a/src/cpu/x86/Kconfig
+++ b/src/cpu/x86/Kconfig
@@ -120,7 +120,7 @@
 	help
 	  SMM support without PARALLEL_MP, to be deprecated.
 
-if SMM_TSEG
+if HAVE_SMI_HANDLER && !SMM_LEGACY_ASEG
 
 config SMM_MODULE_HEAP_SIZE
 	hex
diff --git a/src/cpu/x86/smm/Makefile.inc b/src/cpu/x86/smm/Makefile.inc
index 36aa113..cd920da 100644
--- a/src/cpu/x86/smm/Makefile.inc
+++ b/src/cpu/x86/smm/Makefile.inc
@@ -35,6 +35,10 @@
 romstage-y += tseg_region.c
 postcar-y += tseg_region.c
 
+endif
+
+ifeq ($(CONFIG_PARALLEL_MP),y)
+
 smmstub-y += smm_stub.S
 
 smm-y += smm_module_handler.c
@@ -71,7 +75,9 @@
 $(obj)/smm/smm: $(obj)/smm/smm.elf.rmod
 	$(OBJCOPY_smm) -O binary $< $@
 
-else # CONFIG_SMM_TSEG
+endif
+
+ifeq ($(CONFIG_SMM_LEGACY_ASEG),y)
 
 smm-y += smm.ld
 
@@ -83,4 +89,4 @@
 smm-y += smmhandler.S
 smm-y += smihandler.c
 
-endif # CONFIG_SMM_TSEG
+endif # CONFIG_SMM_LEGACY_ASEG
diff --git a/src/cpu/x86/smm/smm_module_loader.c b/src/cpu/x86/smm/smm_module_loader.c
index beddb3c..14e2aa3 100644
--- a/src/cpu/x86/smm/smm_module_loader.c
+++ b/src/cpu/x86/smm/smm_module_loader.c
@@ -437,6 +437,9 @@
 				     params, fxsave_area_relocation);
 }
 
+static int smm_load_module_aseg(const uintptr_t smram_base, const size_t smram_size,
+				struct smm_loader_params *params);
+
 /*
  *The SMM module is placed within the provided region in the following
  * manner:
@@ -477,6 +480,9 @@
 	size_t total_size = 0;
 	uintptr_t base; /* The base for the permanent handler */
 
+	if (CONFIG(SMM_ASEG))
+		return smm_load_module_aseg(smram_base, smram_size, params);
+
 	if (smram_size <= SMM_DEFAULT_SIZE)
 		return -1;
 
@@ -592,3 +598,97 @@
 
 	return smm_module_setup_stub(base, smram_size, params, fxsave_area);
 }
+
+/*
+ *The SMM module is placed within the provided region in the following
+ * manner:
+ * +-----------------+ <- smram + size == 0x10000
+ * |  save states    |
+ * +-----------------+
+ * |  fxsave area    |
+ * +-----------------+
+ * |  smi handler    |
+ * |      ...        |
+ * +-----------------+ <- cpu0
+ * |    stub code    | <- cpu1
+ * |    stub code    | <- cpu2
+ * |    stub code    | <- cpu3, etc
+ * |                 |
+ * |                 |
+ * |                 |
+ * |    stacks       |
+ * +-----------------+ <- smram start = 0xA0000
+ */
+static int smm_load_module_aseg(const uintptr_t smram_base, const size_t smram_size,
+				struct smm_loader_params *params)
+{
+	struct rmodule smm_mod;
+	struct smm_runtime *handler_mod_params;
+
+	if (smram_size != SMM_DEFAULT_SIZE)
+		return -1;
+
+	if (smram_base != SMM_BASE)
+		return -1;
+
+	/* Fail if can't parse the smm rmodule. */
+	if (rmodule_parse(&_binary_smm_start, &smm_mod))
+		return -1;
+
+	if (!smm_create_map(smram_base, params->num_concurrent_save_states, params)) {
+		printk(BIOS_ERR, "%s: Error creating CPU map\n", __func__);
+		return -1;
+	}
+
+	const uintptr_t entry0_end = cpus[0].code_end;
+	const uintptr_t save_state_base = cpus[params->num_cpus - 1].ss_start;
+	const size_t fxsave_size = FXSAVE_SIZE * params->num_cpus;
+	const uintptr_t fxsave_base = ALIGN_DOWN(save_state_base - fxsave_size, 16);
+
+	if (fxsave_base <= entry0_end) {
+		printk(BIOS_ERR, "%s, fxsave %lx won't fit smram\n", __func__, fxsave_base);
+		return -1;
+	}
+
+	const size_t handler_size = rmodule_memory_size(&smm_mod);
+	const size_t module_alignment = rmodule_load_alignment(&smm_mod);
+	const uintptr_t module_base = ALIGN_DOWN(fxsave_base - handler_size, module_alignment);
+
+	if (module_base <= entry0_end) {
+		printk(BIOS_ERR, "%s, module won't fit smram\n", __func__);
+		return -1;
+	}
+
+	if (rmodule_load((void *)module_base, &smm_mod))
+		return -1;
+
+	params->handler = rmodule_entry(&smm_mod);
+	handler_mod_params = rmodule_parameters(&smm_mod);
+	handler_mod_params->smbase = smram_base;
+	handler_mod_params->smm_size = smram_size;
+	handler_mod_params->save_state_size = params->real_cpu_save_state_size;
+	handler_mod_params->num_cpus = params->num_cpus;
+	handler_mod_params->gnvs_ptr = (uintptr_t)acpi_get_gnvs();
+
+	for (int i = 0; i < params->num_cpus; i++) {
+		handler_mod_params->save_state_top[i] =
+			cpus[i].ss_start + params->per_cpu_save_state_size;
+	}
+
+	printk(BIOS_DEBUG, "%s: smram_start: 0x%lx\n",  __func__, smram_base);
+	printk(BIOS_DEBUG, "%s: smram_end: %lx\n", __func__, smram_base + smram_size);
+	printk(BIOS_DEBUG, "%s: handler start %p\n", __func__, params->handler);
+	printk(BIOS_DEBUG, "%s: handler_size %zx\n", __func__, handler_size);
+	printk(BIOS_DEBUG, "%s: fxsave_area %lx\n", __func__, fxsave_base);
+	printk(BIOS_DEBUG, "%s: fxsave_size %zx\n", __func__, fxsave_size);
+
+	printk(BIOS_DEBUG, "%s: handler_mod_params.smbase = 0x%x\n", __func__,
+	       handler_mod_params->smbase);
+	printk(BIOS_DEBUG, "%s: per_cpu_save_state_size = 0x%x\n", __func__,
+	       handler_mod_params->save_state_size);
+	printk(BIOS_DEBUG, "%s: num_cpus = 0x%x\n", __func__, handler_mod_params->num_cpus);
+	printk(BIOS_DEBUG, "%s: total_save_state_size = 0x%x\n", __func__,
+	       (handler_mod_params->save_state_size * handler_mod_params->num_cpus));
+
+	return smm_module_setup_stub(smram_base, smram_size, params, (void *)fxsave_base);
+}