the following patch was just integrated into master:
commit aa431c0e1774a34b0b6dacd9b0d44de3c82d4922
Author: Evan Lojewski <meklort(a)meklort.com>
Date: Mon Apr 18 20:19:03 2016 -0600
broadwell/me: Fix out-of-bounds array access error
Fix an issue where a broadwell machine without the ME
installed could result in an invalid status code being
reported. For certain values, this would result in the
intel_me_status function never returning. Fix has been
tested on a samus board w and w/o the ME blob installed.
Change-Id: I96667d3b89393f161e4d4efe0544efac98367e6c
Signed-off-by: Evan Lojewski <meklort(a)gmail.com>
Reviewed-on: https://review.coreboot.org/14409
Tested-by: build bot (Jenkins)
Reviewed-by: Duncan Laurie <dlaurie(a)google.com>
See https://review.coreboot.org/14409 for details.
-gerrit
Aaron Durbin (adurbin(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/14605
-gerrit
commit 6b9e0b52e625fbbe5b01d5442d511d212bf7048c
Author: Aaron Durbin <adurbin(a)chromium.org>
Date: Wed May 4 09:00:13 2016 -0500
{cpu,soc}/intel: remove unused smm_init() function
There used to be a need for an empty smm_init() function
because initialize_cpus() called it even though nothing
called initialize_cpus(). However, garbage collection at
link time is implemented so there's no reason to provide an
empty function to satisfy a symbol that is completely culled
during link. Remove it.
Change-Id: Ic13c85f1d3d57e38e7132e4289a98a95829f765a
Signed-off-by: Aaron Durbin <adurbin(a)chromium.org>
---
src/cpu/intel/haswell/smmrelocate.c | 9 ---------
src/soc/intel/baytrail/placeholders.c | 3 ---
src/soc/intel/braswell/smm.c | 4 ----
src/soc/intel/broadwell/smmrelocate.c | 9 ---------
src/soc/intel/fsp_baytrail/placeholders.c | 4 ----
src/soc/intel/skylake/smmrelocate.c | 11 -----------
6 files changed, 40 deletions(-)
diff --git a/src/cpu/intel/haswell/smmrelocate.c b/src/cpu/intel/haswell/smmrelocate.c
index 5c50ad1c..34a3551 100644
--- a/src/cpu/intel/haswell/smmrelocate.c
+++ b/src/cpu/intel/haswell/smmrelocate.c
@@ -352,15 +352,6 @@ void smm_relocate(void)
smm_initiate_relocation();
}
-void smm_init(void)
-{
- /* smm_init() is normally called from initialize_cpus() in
- * lapic_cpu_init.c. However, that path is no longer used. Don't reuse
- * the function name because that would cause confusion.
- * The smm_initialize() function above is used to setup SMM at the
- * appropriate time. */
-}
-
void smm_lock(void)
{
/* LOCK the SMM memory window and enable normal SMM.
diff --git a/src/soc/intel/baytrail/placeholders.c b/src/soc/intel/baytrail/placeholders.c
index 500ced2..b110f5f 100644
--- a/src/soc/intel/baytrail/placeholders.c
+++ b/src/soc/intel/baytrail/placeholders.c
@@ -17,8 +17,5 @@
#include <device/pci_rom.h>
#include <soc/acpi.h>
-
-void smm_init(void) {}
-
/* Rmodules don't like weak symbols. */
u32 map_oprom_vendev(u32 vendev) { return vendev; }
diff --git a/src/soc/intel/braswell/smm.c b/src/soc/intel/braswell/smm.c
index 8318050..3a7ab1c 100644
--- a/src/soc/intel/braswell/smm.c
+++ b/src/soc/intel/braswell/smm.c
@@ -29,10 +29,6 @@
/* Save settings which will be committed in SMI functions. */
static uint32_t smm_save_params[SMM_SAVE_PARAM_COUNT];
-void smm_init(void)
-{
-}
-
void southcluster_smm_save_param(int param, uint32_t data)
{
smm_save_params[param] = data;
diff --git a/src/soc/intel/broadwell/smmrelocate.c b/src/soc/intel/broadwell/smmrelocate.c
index 0cc6399..6fd609b 100644
--- a/src/soc/intel/broadwell/smmrelocate.c
+++ b/src/soc/intel/broadwell/smmrelocate.c
@@ -316,15 +316,6 @@ void smm_relocate(void)
smm_initiate_relocation();
}
-void smm_init(void)
-{
- /* smm_init() is normally called from initialize_cpus() in
- * lapic_cpu_init.c. However, that path is no longer used. Don't reuse
- * the function name because that would cause confusion.
- * The smm_initialize() function above is used to setup SMM at the
- * appropriate time. */
-}
-
void smm_lock(void)
{
/* LOCK the SMM memory window and enable normal SMM.
diff --git a/src/soc/intel/fsp_baytrail/placeholders.c b/src/soc/intel/fsp_baytrail/placeholders.c
index 248aba2..587f0e9 100644
--- a/src/soc/intel/fsp_baytrail/placeholders.c
+++ b/src/soc/intel/fsp_baytrail/placeholders.c
@@ -20,9 +20,5 @@
void acpi_create_serialio_ssdt(acpi_header_t *ssdt) {}
-#if IS_ENABLED(CONFIG_HAVE_SMI_HANDLER)
-void smm_init(void) {}
-#endif
-
/* Rmodules don't like weak symbols. */
u32 map_oprom_vendev(u32 vendev) { return vendev; }
diff --git a/src/soc/intel/skylake/smmrelocate.c b/src/soc/intel/skylake/smmrelocate.c
index fcb89de..9428dcc 100644
--- a/src/soc/intel/skylake/smmrelocate.c
+++ b/src/soc/intel/skylake/smmrelocate.c
@@ -302,17 +302,6 @@ void smm_relocate(void)
smm_initiate_relocation();
}
-void smm_init(void)
-{
- /*
- * smm_init() is normally called from initialize_cpus() in
- * lapic_cpu_init.c. However, that path is no longer used. Don't reuse
- * the function name because that would cause confusion.
- * The smm_initialize() function above is used to setup SMM at the
- * appropriate time.
- */
-}
-
void smm_lock(void)
{
/*
Aaron Durbin (adurbin(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/14561
-gerrit
commit d1afc4d0dbb686cee8a927d7934892a0ebe16cfb
Author: Aaron Durbin <adurbin(a)chromium.org>
Date: Sat Apr 30 15:14:18 2016 -0500
cpu/x86: remove BACKUP_DEFAULT_SMM_REGION option
Unconditionally provide the backup default SMM area API. There's no
reason to guard the symbols behind anything since linker garbage
collection is implemented. A board or chipset is free to use the
code or not without needing to select an option.
Change-Id: I14cf1318136a17f48ba5ae119507918190e25387
Signed-off-by: Aaron Durbin <adurbin(a)chromium.org>
---
src/cpu/intel/haswell/Kconfig | 1 -
src/cpu/x86/Kconfig | 6 ----
src/cpu/x86/Makefile.inc | 1 +
src/cpu/x86/backup_default_smm.c | 64 ++++++++++++++++++++++++++++++++++++
src/cpu/x86/smm/Makefile.inc | 1 -
src/cpu/x86/smm/backup_default_smm.c | 64 ------------------------------------
src/soc/intel/baytrail/Kconfig | 1 -
src/soc/intel/braswell/Kconfig | 1 -
src/soc/intel/broadwell/Kconfig | 1 -
src/soc/intel/skylake/Kconfig | 1 -
10 files changed, 65 insertions(+), 76 deletions(-)
diff --git a/src/cpu/intel/haswell/Kconfig b/src/cpu/intel/haswell/Kconfig
index 779f1d6..ec75391 100644
--- a/src/cpu/intel/haswell/Kconfig
+++ b/src/cpu/intel/haswell/Kconfig
@@ -10,7 +10,6 @@ config CPU_SPECIFIC_OPTIONS
select ARCH_VERSTAGE_X86_32
select ARCH_ROMSTAGE_X86_32
select ARCH_RAMSTAGE_X86_32
- select BACKUP_DEFAULT_SMM_REGION
select HAVE_MONOTONIC_TIMER
select SMP
select MMX
diff --git a/src/cpu/x86/Kconfig b/src/cpu/x86/Kconfig
index 6cd65cc..e80f02b 100644
--- a/src/cpu/x86/Kconfig
+++ b/src/cpu/x86/Kconfig
@@ -127,12 +127,6 @@ config PLATFORM_USES_FSP1_0
Selected for Intel processors/platform combinations that use the
Intel Firmware Support Package (FSP) 1.0 for initialization.
-config BACKUP_DEFAULT_SMM_REGION
- def_bool n
- help
- The CPU support will select this option if the default SMM region
- needs to be backed up for suspend/resume purposes.
-
config MIRROR_PAYLOAD_TO_RAM_BEFORE_LOADING
def_bool n
help
diff --git a/src/cpu/x86/Makefile.inc b/src/cpu/x86/Makefile.inc
index 0efbdd7..1724a06 100644
--- a/src/cpu/x86/Makefile.inc
+++ b/src/cpu/x86/Makefile.inc
@@ -5,6 +5,7 @@ endif
subdirs-$(CONFIG_PARALLEL_MP) += name
ramstage-$(CONFIG_PARALLEL_MP) += mp_init.c
ramstage-$(CONFIG_MIRROR_PAYLOAD_TO_RAM_BEFORE_LOADING) += mirror_payload.c
+ramstage-y += backup_default_smm.c
additional-dirs += $(obj)/cpu/x86
diff --git a/src/cpu/x86/backup_default_smm.c b/src/cpu/x86/backup_default_smm.c
new file mode 100644
index 0000000..2023aed
--- /dev/null
+++ b/src/cpu/x86/backup_default_smm.c
@@ -0,0 +1,64 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2014 Google Inc
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of
+ * the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <string.h>
+#include <arch/acpi.h>
+#include <console/console.h>
+#include <cbmem.h>
+#include <cpu/x86/smm.h>
+
+void *backup_default_smm_area(void)
+{
+ void *save_area;
+ const void *default_smm = (void *)SMM_DEFAULT_BASE;
+
+ if (!IS_ENABLED(CONFIG_HAVE_ACPI_RESUME))
+ return NULL;
+
+ /*
+ * The buffer needs to be preallocated regardless. In the non-resume
+ * path it will be allocated for handling resume. Note that cbmem_add()
+ * does a find before the addition.
+ */
+ save_area = cbmem_add(CBMEM_ID_SMM_SAVE_SPACE, SMM_DEFAULT_SIZE);
+
+ if (save_area == NULL) {
+ printk(BIOS_DEBUG, "SMM save area not added.\n");
+ return NULL;
+ }
+
+ /* Only back up the area on S3 resume. */
+ if (acpi_is_wakeup_s3()) {
+ memcpy(save_area, default_smm, SMM_DEFAULT_SIZE);
+ return save_area;
+ }
+
+ /*
+ * Not the S3 resume path. No need to restore memory contents after
+ * SMM relocation.
+ */
+ return NULL;
+}
+
+void restore_default_smm_area(void *smm_save_area)
+{
+ void *default_smm = (void *)SMM_DEFAULT_BASE;
+
+ if (smm_save_area == NULL)
+ return;
+
+ memcpy(default_smm, smm_save_area, SMM_DEFAULT_SIZE);
+}
diff --git a/src/cpu/x86/smm/Makefile.inc b/src/cpu/x86/smm/Makefile.inc
index 72c9796..32f5ea7 100644
--- a/src/cpu/x86/smm/Makefile.inc
+++ b/src/cpu/x86/smm/Makefile.inc
@@ -13,7 +13,6 @@
## GNU General Public License for more details.
##
-ramstage-$(CONFIG_BACKUP_DEFAULT_SMM_REGION) += backup_default_smm.c
ramstage-y += smm_module_loader.c
ifeq ($(CONFIG_ARCH_RAMSTAGE_X86_32),y)
diff --git a/src/cpu/x86/smm/backup_default_smm.c b/src/cpu/x86/smm/backup_default_smm.c
deleted file mode 100644
index 2023aed..0000000
--- a/src/cpu/x86/smm/backup_default_smm.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright (C) 2014 Google Inc
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; version 2 of
- * the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <string.h>
-#include <arch/acpi.h>
-#include <console/console.h>
-#include <cbmem.h>
-#include <cpu/x86/smm.h>
-
-void *backup_default_smm_area(void)
-{
- void *save_area;
- const void *default_smm = (void *)SMM_DEFAULT_BASE;
-
- if (!IS_ENABLED(CONFIG_HAVE_ACPI_RESUME))
- return NULL;
-
- /*
- * The buffer needs to be preallocated regardless. In the non-resume
- * path it will be allocated for handling resume. Note that cbmem_add()
- * does a find before the addition.
- */
- save_area = cbmem_add(CBMEM_ID_SMM_SAVE_SPACE, SMM_DEFAULT_SIZE);
-
- if (save_area == NULL) {
- printk(BIOS_DEBUG, "SMM save area not added.\n");
- return NULL;
- }
-
- /* Only back up the area on S3 resume. */
- if (acpi_is_wakeup_s3()) {
- memcpy(save_area, default_smm, SMM_DEFAULT_SIZE);
- return save_area;
- }
-
- /*
- * Not the S3 resume path. No need to restore memory contents after
- * SMM relocation.
- */
- return NULL;
-}
-
-void restore_default_smm_area(void *smm_save_area)
-{
- void *default_smm = (void *)SMM_DEFAULT_BASE;
-
- if (smm_save_area == NULL)
- return;
-
- memcpy(default_smm, smm_save_area, SMM_DEFAULT_SIZE);
-}
diff --git a/src/soc/intel/baytrail/Kconfig b/src/soc/intel/baytrail/Kconfig
index 8de32de..fcf382e 100644
--- a/src/soc/intel/baytrail/Kconfig
+++ b/src/soc/intel/baytrail/Kconfig
@@ -11,7 +11,6 @@ config CPU_SPECIFIC_OPTIONS
select ARCH_VERSTAGE_X86_32
select ARCH_ROMSTAGE_X86_32
select ARCH_RAMSTAGE_X86_32
- select BACKUP_DEFAULT_SMM_REGION
select CACHE_MRC_SETTINGS
select CPU_INTEL_TURBO_NOT_PACKAGE_SCOPED
select SUPPORT_CPU_UCODE_IN_CBFS
diff --git a/src/soc/intel/braswell/Kconfig b/src/soc/intel/braswell/Kconfig
index 053aa29..3c6f788 100644
--- a/src/soc/intel/braswell/Kconfig
+++ b/src/soc/intel/braswell/Kconfig
@@ -11,7 +11,6 @@ config CPU_SPECIFIC_OPTIONS
select ARCH_RAMSTAGE_X86_32
select ARCH_ROMSTAGE_X86_32
select ARCH_VERSTAGE_X86_32
- select BACKUP_DEFAULT_SMM_REGION
select CACHE_MRC_SETTINGS
select CACHE_RELOCATED_RAMSTAGE_OUTSIDE_CBMEM if RELOCATABLE_RAMSTAGE
select COLLECT_TIMESTAMPS
diff --git a/src/soc/intel/broadwell/Kconfig b/src/soc/intel/broadwell/Kconfig
index 33644e8..1c29d77 100644
--- a/src/soc/intel/broadwell/Kconfig
+++ b/src/soc/intel/broadwell/Kconfig
@@ -11,7 +11,6 @@ config CPU_SPECIFIC_OPTIONS
select ARCH_VERSTAGE_X86_32
select ARCH_ROMSTAGE_X86_32
select ARCH_RAMSTAGE_X86_32
- select BACKUP_DEFAULT_SMM_REGION
select CACHE_MRC_SETTINGS
select MRC_SETTINGS_PROTECT
select CACHE_RELOCATED_RAMSTAGE_OUTSIDE_CBMEM if RELOCATABLE_RAMSTAGE
diff --git a/src/soc/intel/skylake/Kconfig b/src/soc/intel/skylake/Kconfig
index 302b575..0b7dc8c 100644
--- a/src/soc/intel/skylake/Kconfig
+++ b/src/soc/intel/skylake/Kconfig
@@ -12,7 +12,6 @@ config CPU_SPECIFIC_OPTIONS
select ARCH_ROMSTAGE_X86_32
select ARCH_VERSTAGE_X86_32
select ACPI_NHLT
- select BACKUP_DEFAULT_SMM_REGION
select CACHE_MRC_SETTINGS
select CACHE_RELOCATED_RAMSTAGE_OUTSIDE_CBMEM if RELOCATABLE_RAMSTAGE
select COLLECT_TIMESTAMPS
Aaron Durbin (adurbin(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/14598
-gerrit
commit f59ecd160238e131c7f6365616231a752e7d356a
Author: Aaron Durbin <adurbin(a)chromium.org>
Date: Tue May 3 17:49:57 2016 -0500
cpu/x86/mp_init: reduce exposure of internal implementation
With all users converted to using the mp_ops callbacks there's
no need to expose that surface area. Therefore, keep it all
within the mp_init compilation unit.
Change-Id: Ia1cc5326c1fa5ffde86b90d805b8379f4e4f46cd
Signed-off-by: Aaron Durbin <adurbin(a)chromium.org>
---
src/cpu/x86/mp_init.c | 78 ++++++++++++++++++++++++++++++++++++++++++++--
src/include/cpu/x86/mp.h | 81 ------------------------------------------------
2 files changed, 75 insertions(+), 84 deletions(-)
diff --git a/src/cpu/x86/mp_init.c b/src/cpu/x86/mp_init.c
index 362cda3..b9084c7 100644
--- a/src/cpu/x86/mp_init.c
+++ b/src/cpu/x86/mp_init.c
@@ -38,6 +38,57 @@
#include <thread.h>
#define MAX_APIC_IDS 256
+
+typedef void (*mp_callback_t)(void);
+
+/*
+ * A mp_flight_record details a sequence of calls for the APs to perform
+ * along with the BSP to coordinate sequencing. Each flight record either
+ * provides a barrier for each AP before calling the callback or the APs
+ * are allowed to perform the callback without waiting. Regardless, each
+ * record has the cpus_entered field incremented for each record. When
+ * the BSP observes that the cpus_entered matches the number of APs
+ * the bsp_call is called with bsp_arg and upon returning releases the
+ * barrier allowing the APs to make further progress.
+ *
+ * Note that ap_call() and bsp_call() can be NULL. In the NULL case the
+ * callback will just not be called.
+ */
+struct mp_flight_record {
+ atomic_t barrier;
+ atomic_t cpus_entered;
+ mp_callback_t ap_call;
+ mp_callback_t bsp_call;
+} __attribute__((aligned(CACHELINE_SIZE)));
+
+#define _MP_FLIGHT_RECORD(barrier_, ap_func_, bsp_func_) \
+ { \
+ .barrier = ATOMIC_INIT(barrier_), \
+ .cpus_entered = ATOMIC_INIT(0), \
+ .ap_call = ap_func_, \
+ .bsp_call = bsp_func_, \
+ }
+
+#define MP_FR_BLOCK_APS(ap_func_, bsp_func_) \
+ _MP_FLIGHT_RECORD(0, ap_func_, bsp_func_)
+
+#define MP_FR_NOBLOCK_APS(ap_func_, bsp_func_) \
+ _MP_FLIGHT_RECORD(1, ap_func_, bsp_func_)
+
+/* The mp_params structure provides the arguments to the mp subsystem
+ * for bringing up APs. */
+struct mp_params {
+ int num_cpus; /* Total cpus include BSP */
+ int parallel_microcode_load;
+ const void *microcode_pointer;
+ /* adjust_apic_id() is called for every potential apic id in the
+ * system up from 0 to CONFIG_MAX_CPUS. Return adjusted apic_id. */
+ int (*adjust_apic_id)(int index, int apic_id);
+ /* Flight plan for APs and BSP. */
+ struct mp_flight_record *flight_plan;
+ int num_records;
+};
+
/* This needs to match the layout in the .module_parametrs section. */
struct sipi_params {
uint16_t gdtlimit;
@@ -514,7 +565,26 @@ static void init_bsp(struct bus *cpu_bus)
cpus[info->index].apic_id = cpu_path.apic.apic_id;
}
-int mp_init(struct bus *cpu_bus, struct mp_params *p)
+/*
+ * mp_init() will set up the SIPI vector and bring up the APs according to
+ * mp_params. Each flight record will be executed according to the plan. Note
+ * that the MP infrastructure uses SMM default area without saving it. It's
+ * up to the chipset or mainboard to either e820 reserve this area or save this
+ * region prior to calling mp_init() and restoring it after mp_init returns.
+ *
+ * At the time mp_init() is called the MTRR MSRs are mirrored into APs then
+ * caching is enabled before running the flight plan.
+ *
+ * The MP initialization has the following properties:
+ * 1. APs are brought up in parallel.
+ * 2. The ordering of coreboot cpu number and APIC ids is not deterministic.
+ * Therefore, one cannot rely on this property or the order of devices in
+ * the device tree unless the chipset or mainboard know the APIC ids
+ * a priori.
+ *
+ * mp_init() returns < 0 on error, 0 on success.
+ */
+static int mp_init(struct bus *cpu_bus, struct mp_params *p)
{
int num_cpus;
int num_aps;
@@ -563,14 +633,16 @@ int mp_init(struct bus *cpu_bus, struct mp_params *p)
return bsp_do_flight_plan(p);
}
-void mp_initialize_cpu(void)
+/* Calls cpu_initialize(info->index) which calls the coreboot CPU drivers. */
+static void mp_initialize_cpu(void)
{
/* Call back into driver infrastructure for the AP initialization. */
struct cpu_info *info = cpu_info();
cpu_initialize(info->index);
}
-int mp_get_apic_id(int cpu_slot)
+/* Returns apic id for coreboot cpu number or < 0 on failure. */
+static int mp_get_apic_id(int cpu_slot)
{
if (cpu_slot >= CONFIG_MAX_CPUS || cpu_slot < 0)
return -1;
diff --git a/src/include/cpu/x86/mp.h b/src/include/cpu/x86/mp.h
index ff88a20..9742df0 100644
--- a/src/include/cpu/x86/mp.h
+++ b/src/include/cpu/x86/mp.h
@@ -29,56 +29,6 @@ static inline void mfence(void)
__asm__ __volatile__("mfence\t\n": : :"memory");
}
-typedef void (*mp_callback_t)(void);
-
-/*
- * A mp_flight_record details a sequence of calls for the APs to perform
- * along with the BSP to coordinate sequencing. Each flight record either
- * provides a barrier for each AP before calling the callback or the APs
- * are allowed to perform the callback without waiting. Regardless, each
- * record has the cpus_entered field incremented for each record. When
- * the BSP observes that the cpus_entered matches the number of APs
- * the bsp_call is called with bsp_arg and upon returning releases the
- * barrier allowing the APs to make further progress.
- *
- * Note that ap_call() and bsp_call() can be NULL. In the NULL case the
- * callback will just not be called.
- */
-struct mp_flight_record {
- atomic_t barrier;
- atomic_t cpus_entered;
- mp_callback_t ap_call;
- mp_callback_t bsp_call;
-} __attribute__((aligned(CACHELINE_SIZE)));
-
-#define _MP_FLIGHT_RECORD(barrier_, ap_func_, bsp_func_) \
- { \
- .barrier = ATOMIC_INIT(barrier_), \
- .cpus_entered = ATOMIC_INIT(0), \
- .ap_call = ap_func_, \
- .bsp_call = bsp_func_, \
- }
-
-#define MP_FR_BLOCK_APS(ap_func_, bsp_func_) \
- _MP_FLIGHT_RECORD(0, ap_func_, bsp_func_)
-
-#define MP_FR_NOBLOCK_APS(ap_func_, bsp_func_) \
- _MP_FLIGHT_RECORD(1, ap_func_, bsp_func_)
-
-/* The mp_params structure provides the arguments to the mp subsystem
- * for bringing up APs. */
-struct mp_params {
- int num_cpus; /* Total cpus include BSP */
- int parallel_microcode_load;
- const void *microcode_pointer;
- /* adjust_apic_id() is called for every potential apic id in the
- * system up from 0 to CONFIG_MAX_CPUS. Return adjusted apic_id. */
- int (*adjust_apic_id)(int index, int apic_id);
- /* Flight plan for APs and BSP. */
- struct mp_flight_record *flight_plan;
- int num_records;
-};
-
/* The sequence of the callbacks are in calling order. */
struct mp_ops {
/*
@@ -175,37 +125,6 @@ struct mp_ops {
int mp_init_with_smm(struct bus *cpu_bus, const struct mp_ops *mp_ops);
/*
- * mp_init() will set up the SIPI vector and bring up the APs according to
- * mp_params. Each flight record will be executed according to the plan. Note
- * that the MP infrastructure uses SMM default area without saving it. It's
- * up to the chipset or mainboard to either e820 reserve this area or save this
- * region prior to calling mp_init() and restoring it after mp_init returns.
- *
- * At the time mp_init() is called the MTRR MSRs are mirrored into APs then
- * caching is enabled before running the flight plan.
- *
- * The MP initialization has the following properties:
- * 1. APs are brought up in parallel.
- * 2. The ordering of coreboot cpu number and APIC ids is not deterministic.
- * Therefore, one cannot rely on this property or the order of devices in
- * the device tree unless the chipset or mainboard know the APIC ids
- * a priori.
- *
- * mp_init() returns < 0 on error, 0 on success.
- */
-int mp_init(struct bus *cpu_bus, struct mp_params *params);
-
-/*
- * Useful functions to use in flight records when sequencing APs.
- */
-
-/* Calls cpu_initialize(info->index) which calls the coreboot CPU drivers. */
-void mp_initialize_cpu(void);
-
-/* Returns apic id for coreboot cpu number or < 0 on failure. */
-int mp_get_apic_id(int cpu_slot);
-
-/*
* SMM helpers to use with initializing CPUs.
*/
Aaron Durbin (adurbin(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/14557
-gerrit
commit dc2551ff243d548d69ae1719df905f9a95f527d0
Author: Aaron Durbin <adurbin(a)chromium.org>
Date: Fri Apr 29 22:55:49 2016 -0500
cpu/x86: combine multiprocessor and SMM initialization
In order to reduce code duplication provide a common flow
through callback functions that performs the multiprocessor
and optionally SMM initialization. The existing MP flight
records are utilized but a common flow is provided such
that the chipset/cpu only needs to provide a mp_ops
structure which has callbacks to gather info and provide
hooks at certain points in the sequence.
All current users of the MP code can be switched over to
this flow since there haven't been any flight records that
are overly complicated and long. After the conversion
has taken place most of the surface area of the MP
API can be hidden away within the compilation unit proper.
Change-Id: I6f70969631012982126f0d0d76e5fac6880c24f0
Signed-off-by: Aaron Durbin <adurbin(a)chromium.org>
---
src/cpu/x86/mp_init.c | 242 +++++++++++++++++++++++++++++++++++++++++++++++
src/include/cpu/x86/mp.h | 96 +++++++++++++++++++
2 files changed, 338 insertions(+)
diff --git a/src/cpu/x86/mp_init.c b/src/cpu/x86/mp_init.c
index 2180d98..362cda3 100644
--- a/src/cpu/x86/mp_init.c
+++ b/src/cpu/x86/mp_init.c
@@ -607,3 +607,245 @@ void smm_initiate_relocation(void)
smm_initiate_relocation_parallel();
spin_unlock(&smm_relocation_lock);
}
+
+struct mp_state {
+ struct mp_ops ops;
+ int cpu_count;
+ uintptr_t perm_smbase;
+ size_t perm_smsize;
+ size_t smm_save_state_size;
+ int do_smm;
+} mp_state;
+
+static int is_smm_enabled(void)
+{
+ return IS_ENABLED(CONFIG_HAVE_SMI_HANDLER) && mp_state.do_smm;
+}
+
+static void smm_disable(void)
+{
+ mp_state.do_smm = 0;
+}
+
+static void smm_enable(void)
+{
+ if (IS_ENABLED(CONFIG_HAVE_SMI_HANDLER))
+ mp_state.do_smm = 1;
+}
+
+static void asmlinkage smm_do_relocation(void *arg)
+{
+ const struct smm_module_params *p;
+ const struct smm_runtime *runtime;
+ int cpu;
+ uintptr_t curr_smbase;
+ uintptr_t perm_smbase;
+
+ p = arg;
+ runtime = p->runtime;
+ cpu = p->cpu;
+ curr_smbase = runtime->smbase;
+
+ if (cpu >= CONFIG_MAX_CPUS) {
+ printk(BIOS_CRIT,
+ "Invalid CPU number assigned in SMM stub: %d\n", cpu);
+ return;
+ }
+
+ /*
+ * The permanent handler runs with all cpus concurrently. Precalculate
+ * the location of the new SMBASE. If using SMM modules then this
+ * calculation needs to match that of the module loader.
+ */
+ perm_smbase = mp_state.perm_smbase;
+ perm_smbase -= cpu * runtime->save_state_size;
+
+ printk(BIOS_DEBUG, "New SMBASE 0x%08lx\n", perm_smbase);
+
+ /* Setup code checks this callback for validity. */
+ mp_state.ops.relocation_handler(cpu, curr_smbase, perm_smbase);
+}
+
+static void adjust_smm_apic_id_map(struct smm_loader_params *smm_params)
+{
+ int i;
+ struct smm_runtime *runtime = smm_params->runtime;
+
+ for (i = 0; i < CONFIG_MAX_CPUS; i++)
+ runtime->apic_id_to_cpu[i] = mp_get_apic_id(i);
+}
+
+static int install_relocation_handler(int num_cpus, size_t save_state_size)
+{
+ struct smm_loader_params smm_params = {
+ .per_cpu_stack_size = save_state_size,
+ .num_concurrent_stacks = num_cpus,
+ .per_cpu_save_state_size = save_state_size,
+ .num_concurrent_save_states = 1,
+ .handler = smm_do_relocation,
+ };
+
+ /* Allow callback to override parameters. */
+ if (mp_state.ops.adjust_smm_params != NULL)
+ mp_state.ops.adjust_smm_params(&smm_params, 0);
+
+ if (smm_setup_relocation_handler(&smm_params))
+ return -1;
+
+ adjust_smm_apic_id_map(&smm_params);
+
+ return 0;
+}
+
+static int install_permanent_handler(int num_cpus, uintptr_t smbase,
+ size_t smsize, size_t save_state_size)
+{
+ /* There are num_cpus concurrent stacks and num_cpus concurrent save
+ * state areas. Lastly, set the stack size to the save state size. */
+ struct smm_loader_params smm_params = {
+ .per_cpu_stack_size = save_state_size,
+ .num_concurrent_stacks = num_cpus,
+ .per_cpu_save_state_size = save_state_size,
+ .num_concurrent_save_states = num_cpus,
+ };
+
+ /* Allow callback to override parameters. */
+ if (mp_state.ops.adjust_smm_params != NULL)
+ mp_state.ops.adjust_smm_params(&smm_params, 1);
+
+ printk(BIOS_DEBUG, "Installing SMM handler to 0x%08lx\n", smbase);
+
+ if (smm_load_module((void *)smbase, smsize, &smm_params))
+ return -1;
+
+ adjust_smm_apic_id_map(&smm_params);
+
+ return 0;
+}
+
+/* Load SMM handlers as part of MP flight record. */
+static void load_smm_handlers(void)
+{
+ size_t smm_save_state_size = mp_state.smm_save_state_size;
+
+ /* Do nothing if SMM is disabled.*/
+ if (!is_smm_enabled())
+ return;
+
+ /* Install handlers. */
+ if (install_relocation_handler(mp_state.cpu_count,
+ smm_save_state_size) < 0) {
+ printk(BIOS_ERR, "Unable to install SMM relocation handler.\n");
+ smm_disable();
+ }
+
+ if (install_permanent_handler(mp_state.cpu_count, mp_state.perm_smbase,
+ mp_state.perm_smsize, smm_save_state_size) < 0) {
+ printk(BIOS_ERR, "Unable to install SMM permanent handler.\n");
+ smm_disable();
+ }
+
+ /* Ensure the SMM handlers hit DRAM before performing first SMI. */
+ wbinvd();
+
+ /*
+ * Indicate that the SMM handlers have been loaded and MP
+ * initialization is about to start.
+ */
+ if (is_smm_enabled() && mp_state.ops.pre_mp_smm_init != NULL)
+ mp_state.ops.pre_mp_smm_init();
+}
+
+/* Trigger SMM as part of MP flight record. */
+static void trigger_smm_relocation(void)
+{
+ /* Do nothing if SMM is disabled.*/
+ if (!is_smm_enabled() || mp_state.ops.per_cpu_smm_trigger == NULL)
+ return;
+ /* Trigger SMM mode for the currently running processor. */
+ mp_state.ops.per_cpu_smm_trigger();
+}
+
+static struct mp_flight_record mp_steps[] = {
+ /* Once the APs are up load the SMM handlers. */
+ MP_FR_BLOCK_APS(NULL, load_smm_handlers),
+ /* Perform SMM relocation. */
+ MP_FR_NOBLOCK_APS(trigger_smm_relocation, trigger_smm_relocation),
+ /* Initialize each cpu through the driver framework. */
+ MP_FR_BLOCK_APS(mp_initialize_cpu, mp_initialize_cpu),
+ /* Wait for APs to finish everything else then let them park. */
+ MP_FR_BLOCK_APS(NULL, NULL),
+};
+
+static void fill_mp_state(struct mp_state *state, const struct mp_ops *ops)
+{
+ /*
+ * Make copy of the ops so that defaults can be set in the non-const
+ * structure if needed.
+ */
+ memcpy(&state->ops, ops, sizeof(*ops));
+
+ if (ops->get_cpu_count != NULL)
+ state->cpu_count = ops->get_cpu_count();
+
+ if (ops->get_smm_info != NULL)
+ ops->get_smm_info(&state->perm_smbase, &state->perm_smsize,
+ &state->smm_save_state_size);
+
+ /*
+ * Default to smm_initiate_relocation() if trigger callback isn't
+ * provided.
+ */
+ if (IS_ENABLED(CONFIG_HAVE_SMI_HANDLER) &&
+ ops->per_cpu_smm_trigger == NULL)
+ mp_state.ops.per_cpu_smm_trigger = smm_initiate_relocation;
+}
+
+int mp_init_with_smm(struct bus *cpu_bus, const struct mp_ops *mp_ops)
+{
+ int ret;
+ void *default_smm_area;
+ struct mp_params mp_params;
+
+ if (mp_ops->pre_mp_init != NULL)
+ mp_ops->pre_mp_init();
+
+ fill_mp_state(&mp_state, mp_ops);
+
+ memset(&mp_params, 0, sizeof(mp_params));
+
+ if (mp_state.cpu_count <= 0) {
+ printk(BIOS_ERR, "Invalid cpu_count: %d\n", mp_state.cpu_count);
+ return -1;
+ }
+
+ /* Sanity check SMM state. */
+ if (mp_state.perm_smsize != 0 && mp_state.smm_save_state_size != 0 &&
+ mp_state.ops.relocation_handler != NULL)
+ smm_enable();
+
+ if (is_smm_enabled())
+ printk(BIOS_INFO, "Will perform SMM setup.\n");
+
+ mp_params.num_cpus = mp_state.cpu_count;
+ /* Gather microcode information. */
+ if (mp_state.ops.get_microcode_info != NULL)
+ mp_state.ops.get_microcode_info(&mp_params.microcode_pointer,
+ &mp_params.parallel_microcode_load);
+ mp_params.adjust_apic_id = mp_state.ops.adjust_cpu_apic_entry;
+ mp_params.flight_plan = &mp_steps[0];
+ mp_params.num_records = ARRAY_SIZE(mp_steps);
+
+ /* Perform backup of default SMM area. */
+ default_smm_area = backup_default_smm_area();
+
+ ret = mp_init(cpu_bus, &mp_params);
+
+ restore_default_smm_area(default_smm_area);
+
+ /* Signal callback on success if it's provided. */
+ if (ret == 0 && mp_state.ops.post_mp_init != NULL)
+ mp_state.ops.post_mp_init();
+
+ return ret;
+}
diff --git a/src/include/cpu/x86/mp.h b/src/include/cpu/x86/mp.h
index 3227975..ff88a20 100644
--- a/src/include/cpu/x86/mp.h
+++ b/src/include/cpu/x86/mp.h
@@ -17,6 +17,7 @@
#define _X86_MP_H_
#include <arch/smp/atomic.h>
+#include <cpu/x86/smm.h>
#define CACHELINE_SIZE 64
@@ -78,6 +79,101 @@ struct mp_params {
int num_records;
};
+/* The sequence of the callbacks are in calling order. */
+struct mp_ops {
+ /*
+ * Optionally provide a callback prior to kicking off MP
+ * startup. This callback is done prior to loading the SIPI
+ * vector but after gathering the MP state information. Please
+ * see the sequence below.
+ */
+ void (*pre_mp_init)(void);
+ /*
+ * Return the number of logical x86 execution contexts that
+ * need to be brought out of SIPI state as well as have SMM
+ * handlers installed.
+ */
+ int (*get_cpu_count)(void);
+ /*
+ * Optionally fill in permanent SMM region and save state size. If
+ * this callback is not present no SMM handlers will be installed.
+ * The perm_smsize is the size available to house the permanent SMM
+ * handler.
+ */
+ void (*get_smm_info)(uintptr_t *perm_smbase, size_t *perm_smsize,
+ size_t *smm_save_state_size);
+ /*
+ * Optionally fill in pointer to microcode and indicate if the APs
+ * can load the microcode in parallel.
+ */
+ void (*get_microcode_info)(const void **microcode, int *parallel);
+ /*
+ * Optionally provide a function which adjusts the APIC id
+ * map to cpu number. By default the cpu number and APIC id
+ * are 1:1. To change the APIC id for a given cpu return the
+ * new APIC id. It's called for each cpu as indicated by
+ * get_cpu_count().
+ */
+ int (*adjust_cpu_apic_entry)(int cpu, int cur_apic_id);
+ /*
+ * Optionally adjust SMM handler parameters to override the default
+ * values. The is_perm variable indicates if the parameters to adjust
+ * are for the relocation handler or the permanent handler. This
+ * function is therefore called twice -- once for each handler.
+ * By default the parameters for each SMM handler are:
+ * stack_size num_concurrent_stacks num_concurrent_save_states
+ * relo: save_state_size get_cpu_count() 1
+ * perm: save_state_size get_cpu_count() get_cpu_count()
+ */
+ void (*adjust_smm_params)(struct smm_loader_params *slp, int is_perm);
+ /*
+ * Optionally provide a callback prior to the APs starting SMM
+ * relocation or cpu driver initialization. However, note that
+ * this callback is called after SMM handlers have been loaded.
+ */
+ void (*pre_mp_smm_init)(void);
+ /*
+ * Optional function to use to trigger SMM to perform relocation. If
+ * not provided, smm_initiate_relocation() is used.
+ */
+ void (*per_cpu_smm_trigger)(void);
+ /*
+ * This function is called while each cpu is in the SMM relocation
+ * handler. Its primary purpose is to adjust the SMBASE for the
+ * permanent handler. The parameters passed are the current cpu
+ * running the relocation handler, current SMBASE of relocation handler,
+ * and the pre-calculated staggered cpu SMBASE address of the permanent
+ * SMM handler.
+ */
+ void (*relocation_handler)(int cpu, uintptr_t curr_smbase,
+ uintptr_t staggered_smbase);
+ /*
+ * Optionally provide a callback that is called after the APs
+ * and the BSP have gone through the initialion sequence.
+ */
+ void (*post_mp_init)(void);
+};
+
+/*
+ * mp_init_with_smm() returns < 0 on failure and 0 on success. The mp_ops
+ * argument is used to drive the multiprocess initialization. Unless otherwise
+ * stated each callback is called on the BSP only. The sequence of operations
+ * is the following:
+ * 1. pre_mp_init()
+ * 2. get_cpu_count()
+ * 3. get_smm_info()
+ * 4. get_microcode_info()
+ * 5. adjust_cpu_apic_entry() for each number of get_cpu_count()
+ * 6. adjust_smm_params(is_perm=0)
+ * 7. adjust_smm_params(is_perm=1)
+ * 8. pre_mp_smm_init()
+ * 9. per_cpu_smm_trigger() in parallel for all cpus which calls
+ * relocation_handler() in SMM.
+ * 10. mp_initialize_cpu() for each cpu
+ * 11. post_mp_init()
+ */
+int mp_init_with_smm(struct bus *cpu_bus, const struct mp_ops *mp_ops);
+
/*
* mp_init() will set up the SIPI vector and bring up the APs according to
* mp_params. Each flight record will be executed according to the plan. Note