From 9ede3d51e59e6affff28a77168cb9a4c65bba51c Mon Sep 17 00:00:00 2001 From: Morgan Jang Date: Wed, 6 Nov 2019 10:24:47 +0800 Subject: [PATCH 01/67] src/drivers/ipmi: Implement BMC Get Self Test Result function According to IPMI SPEC, it is recommended that BIOS includes provisions for checking and reporting on the basic health of BMC by executing the Get Self Test Results command and checking the result. TEST=Check the result in response data to confirm the BMC status is fine or not. Change-Id: I20349cec2e8e9420d177d725de2a5560d354fe47 Signed-off-by: Morgan Jang Reviewed-on: https://review.coreboot.org/c/coreboot/+/36638 Tested-by: build bot (Jenkins) Reviewed-by: David Hendricks (cherry picked from commit 50155024141f48cf3048272073d352906a2be0b6) Reviewed-on: https://review.coreboot.org/c/coreboot/+/37087 --- src/drivers/ipmi/ipmi_kcs.h | 13 ++++++++ src/drivers/ipmi/ipmi_kcs_ops.c | 59 +++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/src/drivers/ipmi/ipmi_kcs.h b/src/drivers/ipmi/ipmi_kcs.h index f35802e27b..b3775219c3 100644 --- a/src/drivers/ipmi/ipmi_kcs.h +++ b/src/drivers/ipmi/ipmi_kcs.h @@ -22,6 +22,12 @@ #define IPMI_BMC_GET_DEVICE_ID 0x01 #define IPMI_IPMI_VERSION_MINOR(x) ((x) >> 4) #define IPMI_IPMI_VERSION_MAJOR(x) ((x) & 0xf) +#define IPMI_BMC_GET_SELFTEST_RESULTS 0x04 +#define IPMI_APP_SELFTEST_RESERVED 0xFF +#define IPMI_APP_SELFTEST_NO_ERROR 0x55 +#define IPMI_APP_SELFTEST_NOT_IMPLEMENTED 0x56 +#define IPMI_APP_SELFTEST_ERROR 0x57 +#define IPMI_APP_SELFTEST_FATAL_HW_ERROR 0x58 #define IPMI_NETFN_FIRMWARE 0x08 #define IPMI_NETFN_STORAGE 0x0a @@ -52,4 +58,11 @@ struct ipmi_devid_rsp { uint8_t product_id[2]; } __packed; +/* Get Self Test Results */ +struct ipmi_selftest_rsp { + struct ipmi_rsp resp; + uint8_t result; + uint8_t param; +} __packed; + #endif diff --git a/src/drivers/ipmi/ipmi_kcs_ops.c b/src/drivers/ipmi/ipmi_kcs_ops.c index 90f19dddb8..5cb8995df9 100644 --- a/src/drivers/ipmi/ipmi_kcs_ops.c +++ b/src/drivers/ipmi/ipmi_kcs_ops.c @@ -59,11 +59,34 @@ static int ipmi_get_device_id(struct device *dev, struct ipmi_devid_rsp *rsp) return 0; } +static int ipmi_get_bmc_self_test_result(struct device *dev, struct ipmi_selftest_rsp *rsp) +{ + int ret; + + ret = ipmi_kcs_message(dev->path.pnp.port, IPMI_NETFN_APPLICATION, 0, + IPMI_BMC_GET_SELFTEST_RESULTS, NULL, 0, (u8 *)rsp, + sizeof(*rsp)); + + if (ret < sizeof(struct ipmi_rsp) || rsp->resp.completion_code) { + printk(BIOS_ERR, "IPMI: %s command failed (ret=%d resp=0x%x)\n", + __func__, ret, rsp->resp.completion_code); + return 1; + } + if (ret != sizeof(*rsp)) { + printk(BIOS_ERR, "IPMI: %s response truncated\n", __func__); + return 1; + } + + return 0; +} + static void ipmi_kcs_init(struct device *dev) { struct ipmi_devid_rsp rsp; uint32_t man_id = 0, prod_id = 0; struct drivers_ipmi_config *conf = NULL; + struct ipmi_selftest_rsp selftestrsp; + uint8_t retry_count; if (!dev->enabled) return; @@ -92,6 +115,42 @@ static void ipmi_kcs_init(struct device *dev) } } + printk(BIOS_INFO, "Get BMC self test result..."); + for (retry_count = 0; retry_count < conf->bmc_boot_timeout; retry_count++) { + if (!ipmi_get_bmc_self_test_result(dev, &selftestrsp)) + break; + + mdelay(1000); + } + + switch (selftestrsp.result) { + case IPMI_APP_SELFTEST_NO_ERROR: /* 0x55 */ + printk(BIOS_DEBUG, "No Error\n"); + break; + case IPMI_APP_SELFTEST_NOT_IMPLEMENTED: /* 0x56 */ + printk(BIOS_DEBUG, "Function Not Implemented\n"); + break; + case IPMI_APP_SELFTEST_ERROR: /* 0x57 */ + printk(BIOS_ERR, "BMC: Corrupted or inaccessible data or device\n"); + /* Don't write tables if communication failed */ + dev->enabled = 0; + break; + case IPMI_APP_SELFTEST_FATAL_HW_ERROR: /* 0x58 */ + printk(BIOS_ERR, "BMC: Fatal Hardware Error\n"); + /* Don't write tables if communication failed */ + dev->enabled = 0; + break; + case IPMI_APP_SELFTEST_RESERVED: /* 0xFF */ + printk(BIOS_DEBUG, "Reserved\n"); + break; + + default: /* Other Device Specific Hardware Error */ + printk(BIOS_ERR, "BMC: Device Specific Error\n"); + /* Don't write tables if communication failed */ + dev->enabled = 0; + break; + } + if (!ipmi_get_device_id(dev, &rsp)) { /* Queried the IPMI revision from BMC */ ipmi_revision_minor = IPMI_IPMI_VERSION_MINOR(rsp.ipmi_version); From 556630336244941efcaa6750d954da6dbb0ce72d Mon Sep 17 00:00:00 2001 From: Johnny Lin Date: Thu, 14 Nov 2019 14:55:04 +0800 Subject: [PATCH 02/67] drivers/ipmi: Add IPMI get system GUID support Tested on OCP Mono Lake. Change-Id: I541a23341ccce3d45239babb3f0a8a8c8542b226 Signed-off-by: Johnny Lin Reviewed-on: https://review.coreboot.org/c/coreboot/+/37085 Reviewed-by: David Hendricks Tested-by: build bot (Jenkins) --- src/drivers/ipmi/ipmi_ops.c | 26 ++++++++++++++++++++++++++ src/drivers/ipmi/ipmi_ops.h | 8 ++++++++ 2 files changed, 34 insertions(+) diff --git a/src/drivers/ipmi/ipmi_ops.c b/src/drivers/ipmi/ipmi_ops.c index 784daeb1fb..8a189bdbe1 100644 --- a/src/drivers/ipmi/ipmi_ops.c +++ b/src/drivers/ipmi/ipmi_ops.c @@ -16,6 +16,7 @@ #include #include "ipmi_ops.h" +#include enum cb_err ipmi_init_and_start_bmc_wdt(const int port, uint16_t countdown, uint8_t action) @@ -104,3 +105,28 @@ enum cb_err ipmi_stop_bmc_wdt(const int port) return CB_SUCCESS; } + +enum cb_err ipmi_get_system_guid(const int port, uint8_t *uuid) +{ + int ret; + struct ipmi_get_system_guid_rsp rsp; + + if (uuid == NULL) { + printk(BIOS_ERR, "%s failed, null pointer parameter\n", + __func__); + return CB_ERR; + } + + ret = ipmi_kcs_message(port, IPMI_NETFN_APPLICATION, 0x0, + IPMI_BMC_GET_SYSTEM_GUID, NULL, 0, + (unsigned char *) &rsp, sizeof(rsp)); + + if (ret < sizeof(struct ipmi_rsp) || rsp.resp.completion_code) { + printk(BIOS_ERR, "IPMI: %s command failed (ret=%d resp=0x%x)\n", + __func__, ret, rsp.resp.completion_code); + return CB_ERR; + } + + memcpy(uuid, rsp.data, 16); + return CB_SUCCESS; +} diff --git a/src/drivers/ipmi/ipmi_ops.h b/src/drivers/ipmi/ipmi_ops.h index f293075e90..77fc727cc8 100644 --- a/src/drivers/ipmi/ipmi_ops.h +++ b/src/drivers/ipmi/ipmi_ops.h @@ -21,6 +21,7 @@ #define IPMI_BMC_RESET_WDG_TIMER 0x22 #define IPMI_BMC_SET_WDG_TIMER 0x24 #define IPMI_BMC_GET_WDG_TIMER 0x25 +#define IPMI_BMC_GET_SYSTEM_GUID 0x37 /* BMC watchdog timeout action */ enum ipmi_bmc_timeout_action_type { @@ -44,6 +45,10 @@ struct ipmi_wdt_rsp { uint16_t present_countdown_val; } __packed; +struct ipmi_get_system_guid_rsp { + struct ipmi_rsp resp; + uint8_t data[16]; +} __packed; /* * Initialize and start BMC FRB2 watchdog timer with the * provided timer countdown and action values. @@ -54,4 +59,7 @@ enum cb_err ipmi_init_and_start_bmc_wdt(const int port, uint16_t countdown, /* Returns CB_SUCCESS on success and CB_ERR if an error occurred */ enum cb_err ipmi_stop_bmc_wdt(const int port); +/* IPMI get BMC system GUID and store it to parameter uuid. + * Returns CB_SUCCESS on success and CB_ERR if an error occurred */ +enum cb_err ipmi_get_system_guid(const int port, uint8_t *uuid); #endif From c3a8d63788438bd9c477e88a8cd0de73e981c33e Mon Sep 17 00:00:00 2001 From: Johnny Lin Date: Thu, 14 Nov 2019 15:08:09 +0800 Subject: [PATCH 03/67] mb/ocp/monolake: Override SMBIOS UUID with the value sent by BMC Tested on OCP Mono Lake with dmidecode -t 1 and the expected UUID is visible. Change-Id: I0aab4df67b7aaba8be6ddbb13984fffb2b14fe6b Signed-off-by: Johnny Lin Reviewed-on: https://review.coreboot.org/c/coreboot/+/37086 Tested-by: build bot (Jenkins) Reviewed-by: David Hendricks --- src/mainboard/ocp/monolake/mainboard.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/mainboard/ocp/monolake/mainboard.c b/src/mainboard/ocp/monolake/mainboard.c index dffd19f0f0..a75aae7051 100644 --- a/src/mainboard/ocp/monolake/mainboard.c +++ b/src/mainboard/ocp/monolake/mainboard.c @@ -95,3 +95,9 @@ void smbios_fill_dimm_locator(const struct dimm_info *dimm, struct smbios_type17 dimm->dimm_num); t->bank_locator = smbios_add_string(t->eos, locator); } + +/* Override SMBIOS uuid from the value from BMC. */ +void smbios_system_set_uuid(u8 *uuid) +{ + ipmi_get_system_guid(BMC_KCS_BASE, uuid); +} From e81f20c36a1d2a29825ed60e543cfb427182ff7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ky=C3=B6sti=20M=C3=A4lkki?= Date: Sun, 1 Dec 2019 08:38:11 +0200 Subject: [PATCH 04/67] Revert "console,boot_state: Exclude printk() from reported times" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code in cpu/x86/lapic/apic_timer.c for timer_monotonic_get() is not SMP safe as LAPIC timers do not run as synchronised as TSCs. So the reported times with LAPIC_MONOTONIC_TIMER=y at least were incorrect. Since the approach for this improved times reporting was not completed wrt. the output format either, revert it from 4.11_branch. Change-Id: Ie7edae572cf4fee0b9d2497f7690145c2699a809 Signed-off-by: Kyösti Mälkki Reviewed-on: https://review.coreboot.org/c/coreboot/+/37396 Tested-by: build bot (Jenkins) Reviewed-by: Angel Pons Reviewed-by: Werner Zeh Reviewed-by: Frans Hendriks --- src/arch/x86/postcar_loader.c | 2 -- src/console/printk.c | 46 ----------------------------------- src/include/console/console.h | 7 ------ src/lib/hardwaremain.c | 8 ------ src/lib/prog_loaders.c | 4 --- 5 files changed, 67 deletions(-) diff --git a/src/arch/x86/postcar_loader.c b/src/arch/x86/postcar_loader.c index b53cbf82af..868b770c18 100644 --- a/src/arch/x86/postcar_loader.c +++ b/src/arch/x86/postcar_loader.c @@ -228,8 +228,6 @@ void run_postcar_phase(struct postcar_frame *pcf) /* As postcar exist, it's end of romstage here */ timestamp_add_now(TS_END_ROMSTAGE); - console_time_report(); - prog_set_arg(&prog, cbmem_top()); prog_run(&prog); diff --git a/src/console/printk.c b/src/console/printk.c index 4f9f547bc5..15c599dce0 100644 --- a/src/console/printk.c +++ b/src/console/printk.c @@ -21,56 +21,14 @@ #include #include #include -#include #if (!defined(__PRE_RAM__) && CONFIG(HAVE_ROMSTAGE_CONSOLE_SPINLOCK)) || !CONFIG(HAVE_ROMSTAGE_CONSOLE_SPINLOCK) DECLARE_SPIN_LOCK(console_lock) #endif -#define TRACK_CONSOLE_TIME (CONFIG(HAVE_MONOTONIC_TIMER) && \ - (ENV_RAMSTAGE || !CONFIG(CAR_GLOBAL_MIGRATION))) - -static struct mono_time mt_start, mt_stop; -static long console_usecs; - -static void console_time_run(void) -{ - if (TRACK_CONSOLE_TIME) - timer_monotonic_get(&mt_start); -} - -static void console_time_stop(void) -{ - if (TRACK_CONSOLE_TIME) { - timer_monotonic_get(&mt_stop); - console_usecs += mono_time_diff_microseconds(&mt_start, &mt_stop); - } -} - -void console_time_report(void) -{ - if (!TRACK_CONSOLE_TIME) - return; - - printk(BIOS_DEBUG, "Accumulated console time in " ENV_STRING " %ld ms\n", - DIV_ROUND_CLOSEST(console_usecs, USECS_PER_MSEC)); -} - -long console_time_get_and_reset(void) -{ - if (!TRACK_CONSOLE_TIME) - return 0; - - long elapsed = console_usecs; - console_usecs = 0; - return elapsed; -} - void do_putchar(unsigned char byte) { - console_time_run(); console_tx_byte(byte); - console_time_stop(); } static void wrap_putchar(unsigned char byte, void *data) @@ -103,8 +61,6 @@ int do_vprintk(int msg_level, const char *fmt, va_list args) spin_lock(&console_lock); #endif - console_time_run(); - if (log_this == CONSOLE_LOG_FAST) { i = vtxprintf(wrap_putchar_cbmemc, fmt, args, NULL); } else { @@ -112,8 +68,6 @@ int do_vprintk(int msg_level, const char *fmt, va_list args) console_tx_flush(); } - console_time_stop(); - #ifdef __PRE_RAM__ #if CONFIG(HAVE_ROMSTAGE_CONSOLE_SPINLOCK) spin_unlock(romstage_console_lock()); diff --git a/src/include/console/console.h b/src/include/console/console.h index 607c96862e..1c2a276af0 100644 --- a/src/include/console/console.h +++ b/src/include/console/console.h @@ -64,11 +64,6 @@ asmlinkage void console_init(void); int console_log_level(int msg_level); void do_putchar(unsigned char byte); -/* Return number of microseconds elapsed from start of stage or the previous - get_and_reset() call. */ -long console_time_get_and_reset(void); -void console_time_report(void); - #define printk(LEVEL, fmt, args...) do_printk(LEVEL, fmt, ##args) #define vprintk(LEVEL, fmt, args) do_vprintk(LEVEL, fmt, args) @@ -92,8 +87,6 @@ static inline int console_log_level(int msg_level) { return 0; } static inline void printk(int LEVEL, const char *fmt, ...) {} static inline void vprintk(int LEVEL, const char *fmt, va_list args) {} static inline void do_putchar(unsigned char byte) {} -static inline long console_time_get_and_reset(void) { return 0; } -static inline void console_time_report(void) {} #endif int do_printk(int msg_level, const char *fmt, ...) diff --git a/src/lib/hardwaremain.c b/src/lib/hardwaremain.c index 3fcf8829f3..51ff330d84 100644 --- a/src/lib/hardwaremain.c +++ b/src/lib/hardwaremain.c @@ -63,7 +63,6 @@ static boot_state_t bs_payload_boot(void *arg); struct boot_state_times { int num_samples; struct mono_time samples[MAX_TIME_SAMPLES]; - long console_usecs[MAX_TIME_SAMPLES]; }; /* The prologue (BS_ON_ENTRY) and epilogue (BS_ON_EXIT) of a state can be @@ -242,9 +241,6 @@ static void bs_sample_time(struct boot_state *state) { struct mono_time *mt; - long console_usecs = console_time_get_and_reset(); - state->times.console_usecs[state->times.num_samples] = console_usecs; - mt = &state->times.samples[state->times.num_samples]; timer_monotonic_get(mt); state->times.num_samples++; @@ -261,10 +257,6 @@ static void bs_report_time(struct boot_state *state) run_time = mono_time_diff_microseconds(&samples[1], &samples[2]); exit_time = mono_time_diff_microseconds(&samples[2], &samples[3]); - entry_time -= state->times.console_usecs[1]; - run_time -= state->times.console_usecs[2]; - exit_time -= state->times.console_usecs[3]; - /* Report with millisecond precision to reduce log diffs. */ entry_time = DIV_ROUND_CLOSEST(entry_time, USECS_PER_MSEC); run_time = DIV_ROUND_CLOSEST(run_time, USECS_PER_MSEC); diff --git a/src/lib/prog_loaders.c b/src/lib/prog_loaders.c index 57874967ec..7f320d9597 100644 --- a/src/lib/prog_loaders.c +++ b/src/lib/prog_loaders.c @@ -70,8 +70,6 @@ void run_romstage(void) timestamp_add_now(TS_END_COPYROM); - console_time_report(); - prog_run(&romstage); fail: @@ -155,8 +153,6 @@ void run_ramstage(void) timestamp_add_now(TS_END_COPYRAM); - console_time_report(); - /* This overrides the arg fetched from the relocatable module */ prog_set_arg(&ramstage, cbmem_top()); From 9ad9b3a682ed51ed933fb46ee3b859ca5274310e Mon Sep 17 00:00:00 2001 From: Andrey Petrov Date: Wed, 27 Nov 2019 13:41:36 -0800 Subject: [PATCH 05/67] soc/intel/broadwell_de: Re-read SPD on CRC error I2C bus does not guarantee data integrity. As result, sometimes we end up detecting CRC errors and not adding DIMMs to SMBIOS tables. This change adds re-tries on such errors. TEST=let OCP monolake run without fan and try reading SPD data in tight loop. CRC errors were reported but subsequent retries were error free. Change-Id: I650c8cd80f75b603db332024748a91af6171f096 Signed-off-by: Andrey Petrov Reviewed-on: https://review.coreboot.org/c/coreboot/+/37303 Tested-by: build bot (Jenkins) Reviewed-by: Werner Zeh --- .../intel/fsp_broadwell_de/romstage/memory.c | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/soc/intel/fsp_broadwell_de/romstage/memory.c b/src/soc/intel/fsp_broadwell_de/romstage/memory.c index afbf97bf57..b4bc097e84 100644 --- a/src/soc/intel/fsp_broadwell_de/romstage/memory.c +++ b/src/soc/intel/fsp_broadwell_de/romstage/memory.c @@ -20,6 +20,8 @@ #include #include +#define MAX_SPD_READ_TRIES 3 + static uint32_t get_memory_dclk(void) { uint32_t reg32 = @@ -30,7 +32,7 @@ static uint32_t get_memory_dclk(void) void save_dimm_info(void) { int index = 0; - uint32_t dclk_mhz = 0; + uint32_t dclk_mhz = 0, tries; /* * When talking to SPD chips through IMC slave offset of 0x50 is automagically added @@ -53,9 +55,33 @@ void save_dimm_info(void) for (int slot = 0; slot < CONFIG_DIMM_MAX / IMC_MAX_CHANNELS; slot++) { dimm_attr dimm = {0}; u8 *spd_data = blk.spd_array[index]; - if (spd_decode_ddr4(&dimm, spd_data) == SPD_STATUS_OK) - spd_add_smbios17_ddr4(channel, slot, dclk_mhz, &dimm); + int res = SPD_STATUS_OK; + tries = MAX_SPD_READ_TRIES; + /* + * SMBus controller can't validate data integrity. So on CRC + * error retry a few times. + */ + do { + res = spd_decode_ddr4(&dimm, spd_data); + if (res == SPD_STATUS_CRC_ERROR) { + printk(BIOS_ERR, + "SPD CRC error, channel %u slot %u " + "try %u\n", channel, slot, tries); + get_spd_smbus(&blk); + } + } while (tries-- && res == SPD_STATUS_CRC_ERROR); + index++; + + if (res == SPD_STATUS_CRC_ERROR) { + printk(BIOS_WARNING, "Gave up reading CRC on channel %u" + " slot %u\n", channel, slot); + continue; + } + + if (res == SPD_STATUS_OK) { + spd_add_smbios17_ddr4(channel, slot, dclk_mhz, &dimm); + } } } } From d491ebfe5b559de49f798236f50142ddc8c8fcce Mon Sep 17 00:00:00 2001 From: Andrey Petrov Date: Fri, 15 Nov 2019 13:19:08 -0800 Subject: [PATCH 06/67] [BACKPORT] arch/x86: SMBIOS: Improve core count reporting Current code uses CPUID leaf 0x1, EBX bits 16:23 to determine number for "core count". However, it turns out this number has little to do with real number of cores. According to SDM vol 2A, it stays for "maximum number of addressable IDs for logical processors in this physical package". This does not seem to take into account fusing of giving processor. The new code determines 'core count' by dividing thread-level cpus by reported logical cores. This seems to be the only way to arrive to number of cores as it is reported in official CPU datasheet. TEST=tested on OCP monolake Change-Id: Id4ba9e3079f92ffe38f9104ffcfafe62582dd259 Signed-off-by: Andrey Petrov Reviewed-on: https://review.coreboot.org/c/coreboot/+/36941 Tested-by: build bot (Jenkins) Reviewed-by: Werner Zeh (cherry picked from commit 515ef38db40cc44592770c00be8e4980bbaccc69) Reviewed-on: https://review.coreboot.org/c/coreboot/+/37089 --- src/arch/x86/smbios.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/arch/x86/smbios.c b/src/arch/x86/smbios.c index 725d808d56..7deac63dd6 100644 --- a/src/arch/x86/smbios.c +++ b/src/arch/x86/smbios.c @@ -657,7 +657,26 @@ static int smbios_write_type4(unsigned long *current, int handle) t->processor_version = smbios_processor_name(t->eos); t->processor_family = (res.eax > 0) ? 0x0c : 0x6; t->processor_type = 3; /* System Processor */ - t->core_count = (res.ebx >> 16) & 0xff; + /* + * If CPUID leaf 11 is available, calculate "core count" by dividing + * SMT_ID (logical processors in a core) by Core_ID (number of cores). + * This seems to be the way to arrive to a number of cores mentioned on + * ark.intel.com. + */ + if (cpu_have_cpuid() && cpuid_get_max_func() >= 0xb) { + uint32_t leaf_b_cores = 0, leaf_b_threads = 0; + res = cpuid_ext(0xb, 1); + leaf_b_cores = res.ebx; + res = cpuid_ext(0xb, 0); + leaf_b_threads = res.ebx; + /* if hyperthreading is not available, pretend this is 1 */ + if (leaf_b_threads == 0) { + leaf_b_threads = 1; + } + t->core_count = leaf_b_cores / leaf_b_threads; + } else { + t->core_count = (res.ebx >> 16) & 0xff; + } /* Assume we enable all the cores always, capped only by MAX_CPUS */ t->core_enabled = MIN(t->core_count, CONFIG_MAX_CPUS); t->l1_cache_handle = 0xffff; From 29ce1be9ccc8a16c5ba8b156c9a60ffb27115469 Mon Sep 17 00:00:00 2001 From: Andrey Petrov Date: Wed, 4 Dec 2019 13:39:52 -0800 Subject: [PATCH 07/67] mainboard/facebook/watson: Reclaim unused flash space Currently FMAP does not allocate all the usable space. This change addresses that by removing unused section and expanding CBFS section. TEST=tested on actual watson HW Change-Id: I5f407c11031822d58f11f1a4684845d57653b190 Signed-off-by: Andrey Petrov Reviewed-on: https://review.coreboot.org/c/coreboot/+/37474 Tested-by: build bot (Jenkins) Reviewed-by: Werner Zeh Reviewed-by: Frans Hendriks --- src/mainboard/facebook/watson/board.fmd | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mainboard/facebook/watson/board.fmd b/src/mainboard/facebook/watson/board.fmd index feeb799a8e..e2b8f58d06 100644 --- a/src/mainboard/facebook/watson/board.fmd +++ b/src/mainboard/facebook/watson/board.fmd @@ -20,7 +20,6 @@ FLASH@0xff000000 0x1000000 { # This only exists to satisfy tools that specifically # look for RO_VPD. RO_VPD@0x30000 0x1000 - UNUSED_4@0x31000 0x1cf000 - COREBOOT(CBFS)@0x200000 0x800000 + COREBOOT(CBFS)@0x31000 0x9cf000 } } From 8ac46b937c80822706c9d6c70ce7bbe61eb04f72 Mon Sep 17 00:00:00 2001 From: Johnny Lin Date: Mon, 2 Dec 2019 19:44:04 +0800 Subject: [PATCH 08/67] drivers/ipmi: Add IPMI Read FRU function Implemented according to IPMI "Platform Management FRU Information Storage Definition" specification v1.0 for reading FRU data Product Info Area and Board Info Area. SMBIOS data can be updated with the FRU data. Tested on OCP Mono Lake. Change-Id: Id6353f5ce3f7ddd3bb161b91364b3cf276d020b8 Signed-off-by: Johnny Lin Reviewed-on: https://review.coreboot.org/c/coreboot/+/37444 Tested-by: build bot (Jenkins) Reviewed-by: David Hendricks --- src/drivers/ipmi/Kconfig | 10 + src/drivers/ipmi/Makefile.inc | 1 + src/drivers/ipmi/ipmi_fru.c | 409 ++++++++++++++++++++++++++++++++++ src/drivers/ipmi/ipmi_kcs.h | 1 + src/drivers/ipmi/ipmi_ops.h | 73 ++++++ 5 files changed, 494 insertions(+) create mode 100644 src/drivers/ipmi/ipmi_fru.c diff --git a/src/drivers/ipmi/Kconfig b/src/drivers/ipmi/Kconfig index 0f7152d558..37cfc0d230 100644 --- a/src/drivers/ipmi/Kconfig +++ b/src/drivers/ipmi/Kconfig @@ -8,3 +8,13 @@ config IPMI_KCS_REGISTER_SPACING depends on IPMI_KCS help KCS status and command register IO port address spacing + +config IPMI_FRU_SINGLE_RW_SZ + int + default 16 + depends on IPMI_KCS + help + The data size in a single IPMI FRU read/write command. + IPMB messages are limited to 32-bytes total. When the + data size is larger than this value, IPMI can complete + reading/writing the data over multiple commands. diff --git a/src/drivers/ipmi/Makefile.inc b/src/drivers/ipmi/Makefile.inc index 9d5b3d418f..973fff82c7 100644 --- a/src/drivers/ipmi/Makefile.inc +++ b/src/drivers/ipmi/Makefile.inc @@ -1,3 +1,4 @@ ramstage-$(CONFIG_IPMI_KCS) += ipmi_kcs.c ramstage-$(CONFIG_IPMI_KCS) += ipmi_kcs_ops.c ramstage-$(CONFIG_IPMI_KCS) += ipmi_ops.c +ramstage-$(CONFIG_IPMI_KCS) += ipmi_fru.c diff --git a/src/drivers/ipmi/ipmi_fru.c b/src/drivers/ipmi/ipmi_fru.c new file mode 100644 index 0000000000..a5e6ea60d5 --- /dev/null +++ b/src/drivers/ipmi/ipmi_fru.c @@ -0,0 +1,409 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2019 Wiwynn Corp. + * + * 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 +#include +#include +#include "ipmi_ops.h" + +#define MAX_FRU_BUSY_RETRY 5 +#define READ_FRU_DATA_RETRY_INTERVAL_MS 30 /* From IPMI spec v2.0 rev 1.1 */ +#define OFFSET_LENGTH_MULTIPLIER 8 /* offsets/lengths are multiples of 8 */ +#define NUM_DATA_BYTES(t) (t & 0x3f) /* Encoded in type/length byte */ + +static enum cb_err ipmi_read_fru(const int port, struct ipmi_read_fru_data_req *req, + uint8_t *fru_data) +{ + int ret; + uint8_t total_size; + uint16_t offset = 0; + struct ipmi_read_fru_data_rsp rsp; + int retry_count = 0; + + if (req == NULL || fru_data == NULL) { + printk(BIOS_ERR, "%s failed, null pointer parameter\n", + __func__); + return CB_ERR; + } + + total_size = req->count; + do { + if (req->count > CONFIG_IPMI_FRU_SINGLE_RW_SZ) + req->count = CONFIG_IPMI_FRU_SINGLE_RW_SZ; + + while (retry_count <= MAX_FRU_BUSY_RETRY) { + ret = ipmi_kcs_message(port, IPMI_NETFN_STORAGE, 0x0, + IPMI_READ_FRU_DATA, (const unsigned char *) req, + sizeof(*req), (unsigned char *) &rsp, sizeof(rsp)); + if (rsp.resp.completion_code == 0x81) { + /* Device is busy */ + if (retry_count == MAX_FRU_BUSY_RETRY) { + printk(BIOS_ERR, "IPMI: %s command failed, " + "device busy timeout\n", __func__); + return CB_ERR; + } + printk(BIOS_ERR, "IPMI: FRU device is busy, " + "retry count:%d\n", retry_count); + retry_count++; + mdelay(READ_FRU_DATA_RETRY_INTERVAL_MS); + } else if (ret < sizeof(struct ipmi_rsp) || rsp.resp.completion_code) { + printk(BIOS_ERR, "IPMI: %s command failed (ret=%d resp=0x%x)\n", + __func__, ret, rsp.resp.completion_code); + return CB_ERR; + } + break; + } + retry_count = 0; + memcpy(fru_data + offset, rsp.data, rsp.count); + offset += rsp.count; + total_size -= rsp.count; + req->fru_offset += rsp.count; + req->count = total_size; + } while (total_size > 0); + + return CB_SUCCESS; +} + +/* data: data to check, offset: offset to checksum. */ +static uint8_t checksum(uint8_t *data, int offset) +{ + uint8_t c = 0; + for (; offset > 0; offset--, data++) + c += *data; + return -c; +} + +static uint8_t data2str(const uint8_t *frudata, char *stringdata, uint8_t length) +{ + uint8_t type; + + /* bit[7:6] is the type code. */ + type = ((frudata[0] & 0xc0) >> 6); + if (type != ASCII_8BIT) { + printk(BIOS_ERR, "%s typecode %d is unsupported, FRU string only " + "supports 8-bit ASCII + Latin 1 for now.\n", __func__, type); + return 0; + } + /* In the spec the string data is always the next byte to the type/length byte. */ + memcpy(stringdata, frudata + 1, length); + stringdata[length] = '\0'; + return length; +} + +static void read_fru_board_info_area(const int port, const uint8_t id, + uint8_t offset, struct fru_board_info *info) +{ + uint8_t length; + struct ipmi_read_fru_data_req req; + uint8_t *data_ptr; + + offset = offset * OFFSET_LENGTH_MULTIPLIER; + if (!offset) + return; + req.fru_device_id = id; + /* Read Board Info Area length first. */ + req.fru_offset = offset + 1; + req.count = sizeof(length); + if (ipmi_read_fru(port, &req, &length) != CB_SUCCESS || !length) { + printk(BIOS_ERR, "%s failed, length: %d\n", __func__, length); + return; + } + length = length * OFFSET_LENGTH_MULTIPLIER; + data_ptr = (uint8_t *)malloc(length); + if (!data_ptr) { + printk(BIOS_ERR, "malloc %d bytes for board info failed\n", length); + return; + } + + /* Read Board Info Area data. */ + req.fru_offset = offset; + req.count = length; + if (ipmi_read_fru(port, &req, data_ptr) != CB_SUCCESS) { + printk(BIOS_ERR, "%s failed to read fru\n", __func__); + goto out; + } + if (checksum(data_ptr, length)) { + printk(BIOS_ERR, "Bad FRU board info checksum.\n"); + goto out; + } + /* Read manufacturer string, bit[5:0] is the string length. */ + length = NUM_DATA_BYTES(data_ptr[BOARD_MAN_TYPE_LEN_OFFSET]); + data_ptr += BOARD_MAN_TYPE_LEN_OFFSET; + if (length > 0) { + info->manufacturer = malloc(length + 1); + if (!info->manufacturer) { + printk(BIOS_ERR, "%s failed to malloc %d bytes for " + "manufacturer.\n", __func__, length + 1); + goto out; + } + if (!data2str((const uint8_t *)data_ptr, info->manufacturer, length)) + free(info->manufacturer); + } + + /* Read product name string. */ + data_ptr += length + 1; + length = NUM_DATA_BYTES(data_ptr[0]); + if (length > 0) { + info->product_name = malloc(length+1); + if (!info->product_name) { + printk(BIOS_ERR, "%s failed to malloc %d bytes for " + "product_name.\n", __func__, length + 1); + goto out; + } + if (!data2str((const uint8_t *)data_ptr, info->product_name, length)) + free(info->product_name); + } + + /* Read serial number string. */ + data_ptr += length + 1; + length = NUM_DATA_BYTES(data_ptr[0]); + if (length > 0) { + info->serial_number = malloc(length + 1); + if (!info->serial_number) { + printk(BIOS_ERR, "%s failed to malloc %d bytes for " + "serial_number.\n", __func__, length + 1); + goto out; + } + if (!data2str((const uint8_t *)data_ptr, info->serial_number, length)) + free(info->serial_number); + } + + /* Read part number string. */ + data_ptr += length + 1; + length = NUM_DATA_BYTES(data_ptr[0]); + if (length > 0) { + info->part_number = malloc(length + 1); + if (!info->part_number) { + printk(BIOS_ERR, "%s failed to malloc %d bytes for " + "part_number.\n", __func__, length + 1); + goto out; + } + if (!data2str((const uint8_t *)data_ptr, info->part_number, length)) + free(info->part_number); + } + +out: + free(data_ptr); +} + +static void read_fru_product_info_area(const int port, const uint8_t id, + uint8_t offset, struct fru_product_info *info) +{ + uint8_t length; + struct ipmi_read_fru_data_req req; + uint8_t *data_ptr; + + offset = offset * OFFSET_LENGTH_MULTIPLIER; + if (!offset) + return; + + req.fru_device_id = id; + /* Read Product Info Area length first. */ + req.fru_offset = offset + 1; + req.count = sizeof(length); + if (ipmi_read_fru(port, &req, &length) != CB_SUCCESS || !length) { + printk(BIOS_ERR, "%s failed, length: %d\n", __func__, length); + return; + } + length = length * OFFSET_LENGTH_MULTIPLIER; + data_ptr = (uint8_t *)malloc(length); + if (!data_ptr) { + printk(BIOS_ERR, "malloc %d bytes for product info failed\n", length); + return; + } + + /* Read Product Info Area data. */ + req.fru_offset = offset; + req.count = length; + if (ipmi_read_fru(port, &req, data_ptr) != CB_SUCCESS) { + printk(BIOS_ERR, "%s failed to read fru\n", __func__); + goto out; + } + if (checksum(data_ptr, length)) { + printk(BIOS_ERR, "Bad FRU product info checksum.\n"); + goto out; + } + /* Read manufacturer string, bit[5:0] is the string length. */ + length = NUM_DATA_BYTES(data_ptr[PRODUCT_MAN_TYPE_LEN_OFFSET]); + data_ptr += PRODUCT_MAN_TYPE_LEN_OFFSET; + if (length > 0) { + info->manufacturer = malloc(length + 1); + if (!info->manufacturer) { + printk(BIOS_ERR, "%s failed to malloc %d bytes for " + "manufacturer.\n", __func__, length + 1); + goto out; + } + if (!data2str((const uint8_t *)data_ptr, info->manufacturer, length)) + free(info->manufacturer); + } + + /* Read product_name string. */ + data_ptr += length + 1; + length = NUM_DATA_BYTES(data_ptr[0]); + if (length > 0) { + info->product_name = malloc(length + 1); + if (!info->product_name) { + printk(BIOS_ERR, "%s failed to malloc %d bytes for " + "product_name.\n", __func__, length + 1); + goto out; + } + if (!data2str((const uint8_t *)data_ptr, info->product_name, length)) + free(info->product_name); + } + + /* Read product part/model number. */ + data_ptr += length + 1; + length = NUM_DATA_BYTES(data_ptr[0]); + if (length > 0) { + info->product_partnumber = malloc(length + 1); + if (!info->product_partnumber) { + printk(BIOS_ERR, "%s failed to malloc %d bytes for " + "product_partnumber.\n", __func__, length + 1); + goto out; + } + if (!data2str((const uint8_t *)data_ptr, info->product_partnumber, length)) + free(info->product_partnumber); + } + + /* Read product version string. */ + data_ptr += length + 1; + length = NUM_DATA_BYTES(data_ptr[0]); + if (length > 0) { + info->product_version = malloc(length + 1); + if (!info->product_version) { + printk(BIOS_ERR, "%s failed to malloc %d bytes for " + "product_version.\n", __func__, length + 1); + goto out; + } + if (!data2str((const uint8_t *)data_ptr, info->product_version, length)) + free(info->product_version); + } + + /* Read serial number string. */ + data_ptr += length + 1; + length = NUM_DATA_BYTES(data_ptr[0]); + if (length > 0) { + info->serial_number = malloc(length + 1); + if (!info->serial_number) { + printk(BIOS_ERR, "%s failed to malloc %d bytes for " + "serial_number.\n", __func__, length + 1); + goto out; + } + if (!data2str((const uint8_t *)data_ptr, info->serial_number, length)) + free(info->serial_number); + } + + /* Read asset tag string. */ + data_ptr += length + 1; + length = NUM_DATA_BYTES(data_ptr[0]); + if (length > 0) { + info->asset_tag = malloc(length + 1); + if (!info->asset_tag) { + printk(BIOS_ERR, "%s failed to malloc %d bytes for " + "asset_tag.\n", __func__, length + 1); + goto out; + } + if (!data2str((const uint8_t *)data_ptr, info->asset_tag, length)) + free(info->serial_number); + } + +out: + free(data_ptr); +} + +void read_fru_areas(const int port, const uint8_t id, uint16_t offset, + struct fru_info_str *fru_info_str) +{ + struct ipmi_read_fru_data_req req; + struct ipmi_fru_common_hdr fru_common_hdr; + + /* Set all the char pointers to 0 first, to avoid mainboard + * overwriting SMBIOS string with any non-NULL char pointer + * by accident. */ + memset(fru_info_str, 0, sizeof(*fru_info_str)); + req.fru_device_id = id; + req.fru_offset = offset; + req.count = sizeof(fru_common_hdr); + /* Read FRU common header first */ + if (ipmi_read_fru(port, &req, (uint8_t *)&fru_common_hdr) == CB_SUCCESS) { + if (checksum((uint8_t *)&fru_common_hdr, sizeof(fru_common_hdr))) { + printk(BIOS_ERR, "Bad FRU common header checksum.\n"); + return; + } + printk(BIOS_DEBUG, "FRU common header: format_version: %x\n" + "product_area_offset: %x\n" + "board_area_offset: %x\n" + "chassis_area_offset: %x\n", + fru_common_hdr.format_version, + fru_common_hdr.product_area_offset, + fru_common_hdr.board_area_offset, + fru_common_hdr.chassis_area_offset); + } else { + printk(BIOS_ERR, "Read FRU common header failed\n"); + return; + } + + read_fru_product_info_area(port, id, fru_common_hdr.product_area_offset, + &fru_info_str->prod_info); + read_fru_board_info_area(port, id, fru_common_hdr.board_area_offset, + &fru_info_str->board_info); + /* ToDo: Add read_fru_chassis_info_area(). */ +} + +void read_fru_one_area(const int port, const uint8_t id, uint16_t offset, + struct fru_info_str *fru_info_str, enum fru_area fru_area) +{ + struct ipmi_read_fru_data_req req; + struct ipmi_fru_common_hdr fru_common_hdr; + + req.fru_device_id = id; + req.fru_offset = offset; + req.count = sizeof(fru_common_hdr); + if (ipmi_read_fru(port, &req, (uint8_t *)&fru_common_hdr) == CB_SUCCESS) { + if (checksum((uint8_t *)&fru_common_hdr, sizeof(fru_common_hdr))) { + printk(BIOS_ERR, "Bad FRU common header checksum.\n"); + return; + } + printk(BIOS_DEBUG, "FRU common header: format_version: %x\n" + "product_area_offset: %x\n" + "board_area_offset: %x\n" + "chassis_area_offset: %x\n", + fru_common_hdr.format_version, + fru_common_hdr.product_area_offset, + fru_common_hdr.board_area_offset, + fru_common_hdr.chassis_area_offset); + } else { + printk(BIOS_ERR, "Read FRU common header failed\n"); + return; + } + + switch (fru_area) { + case PRODUCT_INFO_AREA: + memset(&fru_info_str->prod_info, 0, sizeof(fru_info_str->prod_info)); + read_fru_product_info_area(port, id, fru_common_hdr.product_area_offset, + &fru_info_str->prod_info); + break; + case BOARD_INFO_AREA: + memset(&fru_info_str->board_info, 0, sizeof(fru_info_str->board_info)); + read_fru_board_info_area(port, id, fru_common_hdr.board_area_offset, + &fru_info_str->board_info); + break; + /* ToDo: Add case for CHASSIS_INFO_AREA. */ + default: + printk(BIOS_ERR, "Invalid fru_area: %d\n", fru_area); + break; + } +} diff --git a/src/drivers/ipmi/ipmi_kcs.h b/src/drivers/ipmi/ipmi_kcs.h index b3775219c3..9a04377a0a 100644 --- a/src/drivers/ipmi/ipmi_kcs.h +++ b/src/drivers/ipmi/ipmi_kcs.h @@ -31,6 +31,7 @@ #define IPMI_NETFN_FIRMWARE 0x08 #define IPMI_NETFN_STORAGE 0x0a +#define IPMI_READ_FRU_DATA 0x11 #define IPMI_NETFN_TRANSPORT 0x0c #define IPMI_CMD_ACPI_POWERON 0x06 diff --git a/src/drivers/ipmi/ipmi_ops.h b/src/drivers/ipmi/ipmi_ops.h index 77fc727cc8..dd12786b8e 100644 --- a/src/drivers/ipmi/ipmi_ops.h +++ b/src/drivers/ipmi/ipmi_ops.h @@ -49,6 +49,70 @@ struct ipmi_get_system_guid_rsp { struct ipmi_rsp resp; uint8_t data[16]; } __packed; + +struct ipmi_read_fru_data_req { + uint8_t fru_device_id; + uint16_t fru_offset; + uint8_t count; /* count to read, 1-based. */ +} __packed; + +struct ipmi_read_fru_data_rsp { + struct ipmi_rsp resp; + uint8_t count; /* count returned, 1-based. */ + uint8_t data[CONFIG_IPMI_FRU_SINGLE_RW_SZ]; +} __packed; + +/* Platform Management FRU Information Storage Definition Spec. */ +#define PRODUCT_MAN_TYPE_LEN_OFFSET 3 +#define BOARD_MAN_TYPE_LEN_OFFSET 6 + +struct ipmi_fru_common_hdr { + uint8_t format_version; + uint8_t internal_use_area_offset; + uint8_t chassis_area_offset; + uint8_t board_area_offset; + uint8_t product_area_offset; + uint8_t multirecord_area_offset; + uint8_t pad; + uint8_t checksum; +} __packed; + +/* The fru_xxx_info only declares the strings that may be added to SMBIOS. */ +struct fru_product_info { + char *manufacturer; + char *product_name; + char *product_partnumber; + char *product_version; + char *serial_number; + char *asset_tag; +}; + +struct fru_board_info { + char *manufacturer; + char *product_name; + char *serial_number; + char *part_number; +}; + +struct fru_info_str { + struct fru_product_info prod_info; + struct fru_board_info board_info; +}; + +enum typecode { + BINARY = 0, + BCD_PLUS = 1, + ASCII_6BIT = 2, + ASCII_8BIT = 3, +}; + +enum fru_area { + INTERNAL_USE_AREA = 0, + CHASSIS_INFO_AREA = 1, + BOARD_INFO_AREA = 2, + PRODUCT_INFO_AREA = 3, + MULTIRECORD_INFO_AREA = 4, +}; /* * Initialize and start BMC FRB2 watchdog timer with the * provided timer countdown and action values. @@ -62,4 +126,13 @@ enum cb_err ipmi_stop_bmc_wdt(const int port); /* IPMI get BMC system GUID and store it to parameter uuid. * Returns CB_SUCCESS on success and CB_ERR if an error occurred */ enum cb_err ipmi_get_system_guid(const int port, uint8_t *uuid); + +/* Read all FRU inventory areas string data into fru_info_str with + * the same FRU device id. */ +void read_fru_areas(const int port, uint8_t id, uint16_t offset, + struct fru_info_str *fru_info_str); + +/* Read a particular FRU inventory area into fru_info_str. */ +void read_fru_one_area(const int port, uint8_t id, uint16_t offset, + struct fru_info_str *fru_info_str, enum fru_area fru_area); #endif From 93ac30d1891b0f365c42892beb4b189221e44e78 Mon Sep 17 00:00:00 2001 From: Johnny Lin Date: Tue, 3 Dec 2019 18:46:54 +0800 Subject: [PATCH 09/67] mb/ocp/monolake: Override SMBIOS data with IPMI read FRU data SMBIOS type 1 data fields are overwritten by FRU product info area data, SMBIOS type 2 fields are overwritten by FRU board info area data. Tested on OCP Mono Lake. Change-Id: I58cbe95055dea053b115e99f354f40d5902c6a35 Signed-off-by: Johnny Lin Reviewed-on: https://review.coreboot.org/c/coreboot/+/37445 Tested-by: build bot (Jenkins) Reviewed-by: David Hendricks --- src/mainboard/ocp/monolake/Kconfig | 2 + src/mainboard/ocp/monolake/mainboard.c | 87 ++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/src/mainboard/ocp/monolake/Kconfig b/src/mainboard/ocp/monolake/Kconfig index 7d85bbba70..bbc29a334f 100644 --- a/src/mainboard/ocp/monolake/Kconfig +++ b/src/mainboard/ocp/monolake/Kconfig @@ -60,4 +60,6 @@ config FMDFILE config IPMI_KCS_REGISTER_SPACING default 4 +config IPMI_FRU_SINGLE_RW_SZ + default 16 endif # BOARD_OCP_MONOLAKE diff --git a/src/mainboard/ocp/monolake/mainboard.c b/src/mainboard/ocp/monolake/mainboard.c index a75aae7051..9a1c9953ab 100644 --- a/src/mainboard/ocp/monolake/mainboard.c +++ b/src/mainboard/ocp/monolake/mainboard.c @@ -30,6 +30,9 @@ #define VPD_LEN 10 /* Default countdown is 15 minutes. */ #define DEFAULT_COUNTDOWN 9000 +#define FRU_DEVICE_ID 0 + +static struct fru_info_str fru_strings; static void init_frb2_wdt(void) { @@ -76,6 +79,7 @@ static void mainboard_enable(struct device *dev) clear_ipmi_flags(&rsp); system_reset(); } + read_fru_areas(BMC_KCS_BASE, FRU_DEVICE_ID, 0, &fru_strings); } struct chip_operations mainboard_ops = { @@ -101,3 +105,86 @@ void smbios_system_set_uuid(u8 *uuid) { ipmi_get_system_guid(BMC_KCS_BASE, uuid); } +/* Override SMBIOS type 1 data. */ +const char *smbios_system_manufacturer(void) +{ + if (fru_strings.prod_info.manufacturer != NULL) + return (const char *)fru_strings.prod_info.manufacturer; + else + return CONFIG_MAINBOARD_SMBIOS_MANUFACTURER; +} + +const char *smbios_system_product_name(void) +{ + char *prod_name_partnumber; + /* Concatenates IPMI FRU Product Info product name + * and product part number. */ + if (fru_strings.prod_info.product_name != NULL) { + if (fru_strings.prod_info.product_partnumber != NULL) { + /* Append a space after product_name. */ + prod_name_partnumber = strconcat(fru_strings.prod_info.product_name, + " "); + if (!prod_name_partnumber) + return (const char *)fru_strings.prod_info.product_name; + + prod_name_partnumber = strconcat(prod_name_partnumber, + fru_strings.prod_info.product_partnumber); + if (!prod_name_partnumber) + return (const char *)fru_strings.prod_info.product_name; + + return (const char *)prod_name_partnumber; + } else { + return (const char *)fru_strings.prod_info.product_name; + } + } else { + return CONFIG_MAINBOARD_SMBIOS_PRODUCT_NAME; + } +} + +const char *smbios_system_serial_number(void) +{ + if (fru_strings.prod_info.serial_number != NULL) + return (const char *)fru_strings.prod_info.serial_number; + else + return CONFIG_MAINBOARD_SERIAL_NUMBER; +} + +const char *smbios_system_version(void) +{ + if (fru_strings.prod_info.product_version != NULL) + return (const char *)fru_strings.prod_info.product_version; + else + return CONFIG_MAINBOARD_SERIAL_NUMBER; +} +/* Override SMBIOS type 2 data. */ +const char *smbios_mainboard_version(void) +{ + if (fru_strings.board_info.part_number != NULL) + return (const char *)fru_strings.board_info.part_number; + else + return CONFIG_MAINBOARD_VERSION; +} + +const char *smbios_mainboard_manufacturer(void) +{ + if (fru_strings.board_info.manufacturer != NULL) + return (const char *)fru_strings.board_info.manufacturer; + else + return CONFIG_MAINBOARD_SMBIOS_MANUFACTURER; +} + +const char *smbios_mainboard_product_name(void) +{ + if (fru_strings.board_info.product_name != NULL) + return (const char *)fru_strings.board_info.product_name; + else + return CONFIG_MAINBOARD_SMBIOS_PRODUCT_NAME; +} + +const char *smbios_mainboard_serial_number(void) +{ + if (fru_strings.board_info.serial_number != NULL) + return (const char *)fru_strings.board_info.serial_number; + else + return CONFIG_MAINBOARD_SERIAL_NUMBER; +} From 98477da40527aca023e51e42f8d35fbdfae2829b Mon Sep 17 00:00:00 2001 From: Nico Huber Date: Sun, 9 Feb 2020 11:24:32 +0100 Subject: [PATCH 10/67] Makefile.inc: Adapt $(spc) definition GNU Make 4.3 is more picky about the $(spc) definition. It seems, the variable ends up empty. The old definition worked for nearly 8 years, RIP. Tested with GNU Make 4.2.1 and 4.3. Change-Id: I7981e0066b550251ae4a98d7b50e83049fc5586a Signed-off-by: Nico Huber Reviewed-on: https://review.coreboot.org/c/coreboot/+/38790 Reviewed-by: Angel Pons Reviewed-by: Paul Menzel Tested-by: build bot (Jenkins) (cherry picked from commit 0f6f70c3942c152c512b1aa51b6f6079a05e003b) Reviewed-on: https://review.coreboot.org/c/coreboot/+/38958 --- Makefile.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.inc b/Makefile.inc index 66144cd2ac..f26fead343 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -159,7 +159,7 @@ ws_to_under=$(shell echo '$1' | tr ' \t' '_') ####################################################################### # Helper functions for ramstage postprocess spc := -spc += +spc := $(spc) $(spc) comma := , # Returns all files and dirs below `dir` (recursively). From e33ecb0e0842e6e8fbb51280f4495538623af606 Mon Sep 17 00:00:00 2001 From: Martin Roth Date: Sun, 9 Feb 2020 14:30:26 -0700 Subject: [PATCH 11/67] Makefile.inc: Ignore _HID & _ADR conflicts in Broadwell & Lynxpoint We haven't been able to update IASL in 8 months because of this conflict. Ignoring it doesn't make things any worse than they are now. Signed-off-by: Martin Roth Change-Id: Iced2e55e9f2aa7a262a5c1ffeff32af78acfa35e Reviewed-on: https://review.coreboot.org/c/coreboot/+/38810 Tested-by: build bot (Jenkins) Reviewed-by: Angel Pons Reviewed-by: HAOUAS Elyes Reviewed-by: Nico Huber Reviewed-by: Paul Menzel (cherry picked from commit 12e9c5ee86f9aa87b1e84bfc59e6cdbab5a4b254) Reviewed-on: https://review.coreboot.org/c/coreboot/+/38959 Reviewed-by: Patrick Georgi --- Makefile.inc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Makefile.inc b/Makefile.inc index f26fead343..0b09472d39 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -261,7 +261,16 @@ EMPTY_RESOURCE_TEMPLATE_WARNING = 3150 # Redundant offset remarks are not useful in any way and are masking useful # ones that might indicate an issue so it is better to hide them. REDUNDANT_OFFSET_REMARK = 2158 +# Ignore _HID & _ADR coexisting in Intel Lynxpoint and Broadwell ASL code. +# See cb:38803 & cb:38802 +# "Multiple types (Device object requires either a _HID or _ADR, but not both)" +MULTIPLE_TYPES_WARNING = 3073 + +ifeq ($(CONFIG_SOUTHBRIDGE_INTEL_LYNXPOINT)$(CONFIG_SOC_INTEL_BROADWELL),y) +IGNORED_IASL_WARNINGS = -vw $(EMPTY_RESOURCE_TEMPLATE_WARNING) -vw $(REDUNDANT_OFFSET_REMARK) -vw $(MULTIPLE_TYPES_WARNING) +else IGNORED_IASL_WARNINGS = -vw $(EMPTY_RESOURCE_TEMPLATE_WARNING) -vw $(REDUNDANT_OFFSET_REMARK) +endif define asl_template $(CONFIG_CBFS_PREFIX)/$(1).aml-file = $(obj)/$(1).aml From ff6db825c3a42de37b31c93a6694710bdd47d68c Mon Sep 17 00:00:00 2001 From: Jonathan Zhang Date: Sat, 25 Apr 2020 17:22:12 -0700 Subject: [PATCH 12/67] mb/facebook/watson: Make watson as a variant Facebook Watson (V1) board is the first variant of Watson mainboard. Signed-off-by: Jonathan Zhang Change-Id: I1164ee9f8d07cebf8d505ca1e164823c1cb5625c Reviewed-on: https://review.coreboot.org/c/coreboot/+/40541 Tested-by: build bot (Jenkins) Reviewed-by: David Hendricks --- src/mainboard/facebook/watson/Kconfig | 4 ++-- src/mainboard/facebook/watson/Kconfig.name | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mainboard/facebook/watson/Kconfig b/src/mainboard/facebook/watson/Kconfig index 3235b6cc99..4a9d3ef4f5 100644 --- a/src/mainboard/facebook/watson/Kconfig +++ b/src/mainboard/facebook/watson/Kconfig @@ -10,7 +10,7 @@ config BOARD_SPECIFIC_OPTIONS select SERIRQ_CONTINUOUS_MODE select MAINBOARD_USES_IFD_GBE_REGION select MAINBOARD_HAS_LPC_TPM - select MAINBOARD_HAS_TPM1 + select MAINBOARD_HAS_TPM1 if BOARD_FACEBOOK_WATSON select NO_UART_ON_SUPERIO config VBOOT @@ -54,4 +54,4 @@ config ENABLE_TURBO bool "Enable turbo frequency" default n -endif # BOARD_FACEBOOK_WATSON +endif # BOARD_FACEBOOK_WATSON* diff --git a/src/mainboard/facebook/watson/Kconfig.name b/src/mainboard/facebook/watson/Kconfig.name index ea6c344791..1a66168e66 100644 --- a/src/mainboard/facebook/watson/Kconfig.name +++ b/src/mainboard/facebook/watson/Kconfig.name @@ -1,2 +1,2 @@ config BOARD_FACEBOOK_WATSON - bool "Watson" + bool "Watson_v1" From 631eac99ed76def62f2687184db10f3348c1da47 Mon Sep 17 00:00:00 2001 From: Jonathan Zhang Date: Tue, 28 Apr 2020 10:37:15 -0700 Subject: [PATCH 13/67] mb/facebook/watson: add variant watson_v2 Watson V2 is the 2nd board variant of Watson. One aspect of the difference between watson V2 and watson (V1) is: * Watson V2 has TPM2 chip instead of TPM1 chip. * Watson V2 needs to have measured boot enabled. TESTED=Made Watson V2 image, checked boot log and verfied that TPM2 is detected by both coreboot and target OS, that coreboot is measured. TPM: Measured FMAP: COREBOOT CBFS: bootblock into PCR 2 TPM: Measured FMAP: COREBOOT CBFS: fallback/romstage into PCR 2 TPM: Measured FMAP: COREBOOT CBFS: fallback/ramstage into PCR 2 TPM: Measured FMAP: COREBOOT CBFS: cpu_microcode_blob.bin into PCR 2 TPM: Measured FMAP: COREBOOT CBFS: fallback/dsdt.aml into PCR 2 TPM: Measured FMAP: COREBOOT CBFS: fallback/payload into PCR 2 Signed-off-by: Jonathan Zhang Change-Id: Iabf4183dfeabb2f9946dbb5c98c60b7c0cdba711 Reviewed-on: https://review.coreboot.org/c/coreboot/+/40575 Tested-by: build bot (Jenkins) Reviewed-by: David Hendricks --- src/mainboard/facebook/watson/Kconfig | 74 +++++++++++++++++++--- src/mainboard/facebook/watson/Kconfig.name | 3 + 2 files changed, 67 insertions(+), 10 deletions(-) diff --git a/src/mainboard/facebook/watson/Kconfig b/src/mainboard/facebook/watson/Kconfig index 4a9d3ef4f5..009e8b5486 100644 --- a/src/mainboard/facebook/watson/Kconfig +++ b/src/mainboard/facebook/watson/Kconfig @@ -1,4 +1,12 @@ -if BOARD_FACEBOOK_WATSON +if BOARD_FACEBOOK_WATSON || BOARD_FACEBOOK_WATSON_V2 + +config VBOOT + select VBOOT_VBNV_CMOS + select VBOOT_NO_BOARD_SUPPORT + select GBB_FLAG_DISABLE_LID_SHUTDOWN + select GBB_FLAG_DISABLE_PD_SOFTWARE_SYNC + select GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC + select GBB_FLAG_DISABLE_FWMP config BOARD_SPECIFIC_OPTIONS def_bool y @@ -11,15 +19,11 @@ config BOARD_SPECIFIC_OPTIONS select MAINBOARD_USES_IFD_GBE_REGION select MAINBOARD_HAS_LPC_TPM select MAINBOARD_HAS_TPM1 if BOARD_FACEBOOK_WATSON + select MAINBOARD_HAS_TPM2 if BOARD_FACEBOOK_WATSON_V2 select NO_UART_ON_SUPERIO - -config VBOOT - select VBOOT_VBNV_CMOS - select VBOOT_NO_BOARD_SUPPORT - select GBB_FLAG_DISABLE_LID_SHUTDOWN - select GBB_FLAG_DISABLE_PD_SOFTWARE_SYNC - select GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC - select GBB_FLAG_DISABLE_FWMP + select VBOOT if BOARD_FACEBOOK_WATSON_V2 + select VBOOT_MEASURED_BOOT if BOARD_FACEBOOK_WATSON_V2 + select VBOOT_STARTS_IN_ROMSTAGE if BOARD_FACEBOOK_WATSON_V2 config MAINBOARD_DIR string @@ -37,6 +41,55 @@ config CBFS_SIZE hex default 0x00800000 +config VBOOT_FWID_MODEL + string + default "$(CONFIG_MAINBOARD_VENDOR)_$(CONFIG_MAINBOARD_PART_NUMBER)" + +config VBOOT_FIRMWARE_PRIVKEY + string + depends on BOARD_FACEBOOK_WATSON_V2 + default "$(VBOOT_SOURCE)/tests/devkeys/firmware_data_key.vbprivk" + +config VBOOT_FWID_VERSION + string + depends on BOARD_FACEBOOK_WATSON_V2 + default ".$(KERNELVERSION)" + +config VBOOT_KERNEL_KEY + string + depends on BOARD_FACEBOOK_WATSON_V2 + default "$(VBOOT_SOURCE)/tests/devkeys/kernel_subkey.vbpubk" + +config VBOOT_KEYBLOCK + string + depends on BOARD_FACEBOOK_WATSON_V2 + default "$(VBOOT_SOURCE)/tests/devkeys/firmware.keyblock" + +config VBOOT_KEYBLOCK_VERSION + int + depends on BOARD_FACEBOOK_WATSON_V2 + default 1 + +config VBOOT_KEYBLOCK_PREAMBLE_FLAGS + hex + depends on BOARD_FACEBOOK_WATSON_V2 + default 0x0 + +config VBOOT_RECOVERY_KEY + string + depends on BOARD_FACEBOOK_WATSON_V2 + default "$(VBOOT_SOURCE)/tests/devkeys/recovery_key.vbpubk" + +config VBOOT_ROOT_KEY + string + depends on BOARD_FACEBOOK_WATSON_V2 + default "$(VBOOT_SOURCE)/tests/devkeys/root_key.vbpubk" + +config VBOOT_VBNV_OFFSET + hex + depends on BOARD_FACEBOOK_WATSON_V2 + default 0x26 + config VIRTUAL_ROM_SIZE hex # Set to CONFIG_ROM_SIZE*2 if using concatenated flash chips. @@ -48,7 +101,8 @@ config DRIVERS_UART_8250IO config FMDFILE string - default "src/mainboard/$(CONFIG_MAINBOARD_DIR)/board.fmd" + default "src/mainboard/$(CONFIG_MAINBOARD_DIR)/board.fmd" if BOARD_FACEBOOK_WATSON + default "src/mainboard/$(CONFIG_MAINBOARD_DIR)/vboot-ro.fmd" if BOARD_FACEBOOK_WATSON_V2 config ENABLE_TURBO bool "Enable turbo frequency" diff --git a/src/mainboard/facebook/watson/Kconfig.name b/src/mainboard/facebook/watson/Kconfig.name index 1a66168e66..b6a5a66ec2 100644 --- a/src/mainboard/facebook/watson/Kconfig.name +++ b/src/mainboard/facebook/watson/Kconfig.name @@ -1,2 +1,5 @@ config BOARD_FACEBOOK_WATSON bool "Watson_v1" + +config BOARD_FACEBOOK_WATSON_V2 + bool "Watson_v2" From 674a825cd7477fc4339ba9b39a676e1a57dfa93c Mon Sep 17 00:00:00 2001 From: Jonathan Zhang Date: Fri, 15 May 2020 13:37:22 -0700 Subject: [PATCH 14/67] mb/fb/watson/watson_v2: configure PCI bifurcation Watson V2 server has different PCIe bifurcation configuration, comparing to Watson server. Add a watson_v2 variant directory. Allow variant to customize UPD parameters. Configure UPD parameters to define PCIe bifurcation configuration for Watson V2 server. Signed-off-by: Jonathan Zhang Change-Id: I3b57c64dea6f3a468336fcdb1e948dfcd897e60c Reviewed-on: https://review.coreboot.org/c/coreboot/+/41433 Tested-by: build bot (Jenkins) Reviewed-by: Philipp Deppenwiese --- src/mainboard/facebook/watson/Kconfig | 4 ++ src/mainboard/facebook/watson/Makefile.inc | 2 + .../facebook/watson/include/variants.h | 25 ++++++++++ src/mainboard/facebook/watson/romstage.c | 9 ++++ .../watson/variants/watson_v2/Makefile.inc | 1 + .../watson/variants/watson_v2/romstage.c | 48 +++++++++++++++++++ 6 files changed, 89 insertions(+) create mode 100644 src/mainboard/facebook/watson/include/variants.h create mode 100644 src/mainboard/facebook/watson/variants/watson_v2/Makefile.inc create mode 100644 src/mainboard/facebook/watson/variants/watson_v2/romstage.c diff --git a/src/mainboard/facebook/watson/Kconfig b/src/mainboard/facebook/watson/Kconfig index 009e8b5486..f8f93df9b1 100644 --- a/src/mainboard/facebook/watson/Kconfig +++ b/src/mainboard/facebook/watson/Kconfig @@ -41,6 +41,10 @@ config CBFS_SIZE hex default 0x00800000 +config VARIANT_DIR + string + default "watson_v2" if BOARD_FACEBOOK_WATSON_V2 + config VBOOT_FWID_MODEL string default "$(CONFIG_MAINBOARD_VENDOR)_$(CONFIG_MAINBOARD_PART_NUMBER)" diff --git a/src/mainboard/facebook/watson/Makefile.inc b/src/mainboard/facebook/watson/Makefile.inc index 1606476d80..f1384f7c97 100644 --- a/src/mainboard/facebook/watson/Makefile.inc +++ b/src/mainboard/facebook/watson/Makefile.inc @@ -14,3 +14,5 @@ ## ramstage-y += irqroute.c + +CPPFLAGS_common += -I$(src)/mainboard/$(MAINBOARDDIR)/include diff --git a/src/mainboard/facebook/watson/include/variants.h b/src/mainboard/facebook/watson/include/variants.h new file mode 100644 index 0000000000..46989168c9 --- /dev/null +++ b/src/mainboard/facebook/watson/include/variants.h @@ -0,0 +1,25 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * Copyright (C) 2011 Google Inc. + * Copyright (C) Facebook, Inc. and its affiliates + * + * 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. + */ + +#ifndef BASEBOARD_VARIANTS_H +#define BASEBOARD_VARIANTS_H + +#include + +void variant_romstage_fsp_init_params(UPD_DATA_REGION *UpdData); + +#endif /* BASEBOARD_VARIANTS_H */ diff --git a/src/mainboard/facebook/watson/romstage.c b/src/mainboard/facebook/watson/romstage.c index cf52c01f04..b8df798031 100644 --- a/src/mainboard/facebook/watson/romstage.c +++ b/src/mainboard/facebook/watson/romstage.c @@ -17,6 +17,7 @@ #include #include #include +#include /** * /brief mainboard call for setup that needs to be done before fsp init @@ -40,6 +41,14 @@ void late_mainboard_romstage_entry(void) * /brief customize fsp parameters here if needed */ void romstage_fsp_rt_buffer_callback(FSP_INIT_RT_BUFFER *FspRtBuffer) +{ + UPD_DATA_REGION *UpdData = FspRtBuffer->Common.UpdDataRgnPtr; + + /* Variant-specific memory params */ + variant_romstage_fsp_init_params(UpdData); +} + +__weak void variant_romstage_fsp_init_params(UPD_DATA_REGION *UpdData) { } diff --git a/src/mainboard/facebook/watson/variants/watson_v2/Makefile.inc b/src/mainboard/facebook/watson/variants/watson_v2/Makefile.inc new file mode 100644 index 0000000000..29763fb4f6 --- /dev/null +++ b/src/mainboard/facebook/watson/variants/watson_v2/Makefile.inc @@ -0,0 +1 @@ +romstage-y += romstage.c diff --git a/src/mainboard/facebook/watson/variants/watson_v2/romstage.c b/src/mainboard/facebook/watson/variants/watson_v2/romstage.c new file mode 100644 index 0000000000..55f30255e8 --- /dev/null +++ b/src/mainboard/facebook/watson/variants/watson_v2/romstage.c @@ -0,0 +1,48 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * Copyright (C) 2011 Google Inc. + * Copyright (C) Facebook, Inc. and its affiliates + * + * 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 +#include + +void variant_romstage_fsp_init_params(UPD_DATA_REGION *UpdData) +{ + /* Configure IOU1 as 4*4 lanes */ + UpdData->ConfigIOU1_PciPort3 = 0; + + /* Configure IOU2 as 2*4 lanes */ + UpdData->ConfigIOU2_PciPort1 = 0; + + /* Configure PCH PCIe ports as 8*1 lanes */ + UpdData->PchPciPort1 = 1; + UpdData->PchPciPort2 = 1; + UpdData->PchPciPort3 = 1; + UpdData->PchPciPort4 = 1; + UpdData->PchPciPort5 = 1; + UpdData->PchPciPort6 = 1; + UpdData->PchPciPort7 = 1; + UpdData->PchPciPort8 = 1; + + /* Enable hotplug for PCH PCIe ports */ + UpdData->HotPlug_PchPciPort1 = 1; + UpdData->HotPlug_PchPciPort2 = 1; + UpdData->HotPlug_PchPciPort3 = 1; + UpdData->HotPlug_PchPciPort4 = 1; + UpdData->HotPlug_PchPciPort5 = 1; + UpdData->HotPlug_PchPciPort6 = 1; + UpdData->HotPlug_PchPciPort7 = 1; + UpdData->HotPlug_PchPciPort8 = 1; +} From df7e1f9a4345ed4a3db30a8efedea628f3f9fa18 Mon Sep 17 00:00:00 2001 From: Andrey Petrov Date: Mon, 11 Nov 2019 14:27:54 -0800 Subject: [PATCH 15/67] soc/intel/fsp_broadwell_de: Check if memory is 'locked' Under certain conditions TXT can "lock" memory controller for security purpose. This manifests itself in IMC's SMbus controller failing all SPD data read requests. FSP does not detect error condition and fails boot with "No memory found" issue. TEST=tested on OCP monolake in 'locked' state Change-Id: If4637e4293421794a89037ff107e87794c40114a Signed-off-by: Andrey Petrov Reviewed-on: https://review.coreboot.org/c/coreboot/+/42710 Tested-by: build bot (Jenkins) Reviewed-by: Patrick Rudolph Reviewed-by: Christian Walter --- src/soc/intel/fsp_broadwell_de/include/soc/memory.h | 4 ++++ src/soc/intel/fsp_broadwell_de/include/soc/msr.h | 5 +++++ src/soc/intel/fsp_broadwell_de/romstage/memory.c | 8 ++++++++ 3 files changed, 17 insertions(+) diff --git a/src/soc/intel/fsp_broadwell_de/include/soc/memory.h b/src/soc/intel/fsp_broadwell_de/include/soc/memory.h index 3bdba2ef56..494ca34da1 100644 --- a/src/soc/intel/fsp_broadwell_de/include/soc/memory.h +++ b/src/soc/intel/fsp_broadwell_de/include/soc/memory.h @@ -27,4 +27,8 @@ void save_dimm_info(void); +/* Determine if memory configuration has been locked by TXT */ +bool memory_config_is_locked(void); + + #endif diff --git a/src/soc/intel/fsp_broadwell_de/include/soc/msr.h b/src/soc/intel/fsp_broadwell_de/include/soc/msr.h index f9fdffb2bf..2bbcf23687 100644 --- a/src/soc/intel/fsp_broadwell_de/include/soc/msr.h +++ b/src/soc/intel/fsp_broadwell_de/include/soc/msr.h @@ -39,4 +39,9 @@ #define MSR_PRMRR_PHYS_BASE 0x1f4 #define MSR_PRMRR_PHYS_MASK 0x1f5 +/* EDS vol 2 */ +#define MSR_LT_MEMORY_LOCKED 0x2e7 +#define MSR_MEM_LOCK_BIT1 (1 << 1) +#define MSR_MEM_LOCK_BIT2 (1 << 2) + #endif /* _SOC_MSR_H_ */ diff --git a/src/soc/intel/fsp_broadwell_de/romstage/memory.c b/src/soc/intel/fsp_broadwell_de/romstage/memory.c index b4bc097e84..571ab091ab 100644 --- a/src/soc/intel/fsp_broadwell_de/romstage/memory.c +++ b/src/soc/intel/fsp_broadwell_de/romstage/memory.c @@ -13,6 +13,8 @@ * GNU General Public License for more details. */ +#include +#include #include #include #include @@ -85,3 +87,9 @@ void save_dimm_info(void) } } } + +bool memory_config_is_locked(void) +{ + msr_t msr = rdmsr(MSR_LT_MEMORY_LOCKED); + return (msr.lo & (MSR_MEM_LOCK_BIT1 | MSR_MEM_LOCK_BIT2)); +} From c0736c5a55e5e6cfddcb8e804782a2e6b0b13637 Mon Sep 17 00:00:00 2001 From: Johnny Lin Date: Wed, 3 Jun 2020 11:44:22 +0800 Subject: [PATCH 16/67] smbios: Add option VPD_SMBIOS_VERSION that reads BIOS version from a VPD variable If VPD_SMBIOS_VERSION is selected, it would read VPD_RO variable that can override SMBIOS type 0 version. One special scenario of using this feature is to assign a BIOS version to a coreboot image without the need to rebuild from source. VPD_SMBIOS_VERSION default is n. Tested=On OCP Delta Lake, dmidecode -t 0 can see the version being updated from VPD. Change-Id: Iee62ed900095001ffac225fc629b3f2f52045e30 Signed-off-by: Johnny Lin Reviewed-on: https://review.coreboot.org/c/coreboot/+/42029 Tested-by: build bot (Jenkins) Reviewed-by: insomniac Reviewed-by: Julius Werner (cherry picked from commit c746a748c4c5ec6421d7f9f5760717348231d091) Reviewed-on: https://review.coreboot.org/c/coreboot/+/42747 Reviewed-by: Philipp Deppenwiese --- src/Kconfig | 10 ++++++ src/arch/x86/smbios.c | 81 ++++++++++++++++++++++++++++++++----------- 2 files changed, 71 insertions(+), 20 deletions(-) diff --git a/src/Kconfig b/src/Kconfig index ba9ae86067..c0315239fc 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -730,6 +730,16 @@ config SMBIOS_ENCLOSURE_TYPE convertible, or tablet enclosure will be used if the appropriate system type is selected. +config VPD_SMBIOS_VERSION + bool "Populates SMBIOS type 0 version from the VPD_RO variable 'firmware_version'" + default n + depends on VPD && GENERATE_SMBIOS_TABLES + help + Selecting this option will read firmware_version from + VPD_RO and override SMBIOS type 0 version. One special + scenario of using this feature is to assign a BIOS version + to a coreboot image without the need to rebuild from source. + endmenu source "payloads/Kconfig" diff --git a/src/arch/x86/smbios.c b/src/arch/x86/smbios.c index 7deac63dd6..f23e1dc3cd 100644 --- a/src/arch/x86/smbios.c +++ b/src/arch/x86/smbios.c @@ -32,6 +32,8 @@ #if CONFIG(CHROMEOS) #include #endif +#include +#include #define update_max(len, max_len, stmt) \ do { \ @@ -381,12 +383,64 @@ static int create_smbios_type17_for_dimm(struct dimm_info *dimm, return t->length + smbios_string_table_len(t->eos); } +#define VERSION_VPD "firmware_version" +static const char *vpd_get_bios_version(void) +{ + int size; + const char *s; + char *version; + + s = vpd_find(VERSION_VPD, &size, VPD_RO); + if (!s) { + printk(BIOS_ERR, "Find version from VPD %s failed\n", VERSION_VPD); + return NULL; + } + + version = malloc(size + 1); + if (!version) { + printk(BIOS_ERR, "Failed to malloc %d bytes for VPD version\n", size + 1); + return NULL; + } + memcpy(version, s, size); + version[size] = '\0'; + printk(BIOS_DEBUG, "Firmware version %s from VPD %s\n", version, VERSION_VPD); + return version; +} + +static const char *get_bios_version(void) +{ + const char *s; + +#define SPACES \ + " " + + if (CONFIG(CHROMEOS)) + return SPACES; + + if (CONFIG(VPD_SMBIOS_VERSION)) { + s = vpd_get_bios_version(); + if (s != NULL) + return s; + } + + s = smbios_mainboard_bios_version(); + if (s != NULL) + return s; + + if (strlen(CONFIG_LOCALVERSION) != 0) { + printk(BIOS_DEBUG, "BIOS version set to CONFIG_LOCALVERSION: '%s'\n", + CONFIG_LOCALVERSION); + return CONFIG_LOCALVERSION; + } + + printk(BIOS_DEBUG, "SMBIOS firmware version is set to coreboot_version: '%s'\n", + coreboot_version); + return coreboot_version; +} + const char *__weak smbios_mainboard_bios_version(void) { - if (strlen(CONFIG_LOCALVERSION)) - return CONFIG_LOCALVERSION; - else - return coreboot_version; + return NULL; } static int smbios_write_type0(unsigned long *current, int handle) @@ -400,27 +454,14 @@ static int smbios_write_type0(unsigned long *current, int handle) t->length = len - 2; t->vendor = smbios_add_string(t->eos, "coreboot"); -#if !CONFIG(CHROMEOS) t->bios_release_date = smbios_add_string(t->eos, coreboot_dmi_date); - t->bios_version = smbios_add_string(t->eos, - smbios_mainboard_bios_version()); -#else -#define SPACES \ - " " - t->bios_release_date = smbios_add_string(t->eos, coreboot_dmi_date); -#if CONFIG(HAVE_ACPI_TABLES) +#if CONFIG(CHROMEOS) && CONFIG(HAVE_ACPI_TABLES) u32 version_offset = (u32)smbios_string_table_len(t->eos); -#endif - t->bios_version = smbios_add_string(t->eos, SPACES); - -#if CONFIG(HAVE_ACPI_TABLES) /* SMBIOS offsets start at 1 rather than 0 */ - chromeos_get_chromeos_acpi()->vbt10 = - (u32)t->eos + (version_offset - 1); + chromeos_get_chromeos_acpi()->vbt10 = (u32)t->eos + (version_offset - 1); #endif -#endif /* CONFIG_CHROMEOS */ - + t->bios_version = smbios_add_string(t->eos, get_bios_version()); uint32_t rom_size = CONFIG_ROM_SIZE; rom_size = MIN(CONFIG_ROM_SIZE, 16 * MiB); t->bios_rom_size = (rom_size / 65535) - 1; From 380c4b447c55ec014f0bb352d1e2fe5dbe76dbcf Mon Sep 17 00:00:00 2001 From: Jonathan Zhang Date: Mon, 29 Jun 2020 16:22:52 -0700 Subject: [PATCH 17/67] mb/facebook/watson: select VPD_SMBIOS_VERSION Select VPD, GENERATE_SMBIOS_TABLES, VPD_SMBIOS_VERSION so that "firmware_version" key value in RO_VPD is reported in smbios type 0 as BIOS version. TEST=Build coreboot image for WatsonV2, run "vpd -s firmware_version=FB_OSF_1.2 -i RO_VPD -f build/coreboot.rom" command to add firmware_version key value pair in RO_VPD, flash the image to WatsonV2 and reboot it, run dmidecode to verify: [root@localhost ~]# dmidecode -t 0 ... BIOS Information Vendor: coreboot Version: FB_OSF_1.2 ... Signed-off-by: Jonathan Zhang Change-Id: I31fb2cef01161175a0c01094c5445f7fa340f2d0 Reviewed-on: https://review.coreboot.org/c/coreboot/+/42942 Tested-by: build bot (Jenkins) Reviewed-by: Philipp Deppenwiese Reviewed-by: insomniac Reviewed-by: Christian Walter --- src/mainboard/facebook/watson/Kconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mainboard/facebook/watson/Kconfig b/src/mainboard/facebook/watson/Kconfig index f8f93df9b1..2ebc0206cf 100644 --- a/src/mainboard/facebook/watson/Kconfig +++ b/src/mainboard/facebook/watson/Kconfig @@ -12,6 +12,7 @@ config BOARD_SPECIFIC_OPTIONS def_bool y select SOC_INTEL_FSP_BROADWELL_DE select BOARD_ROMSIZE_KB_16384 + select GENERATE_SMBIOS_TABLES select HAVE_ACPI_TABLES select HAVE_OPTION_TABLE select INTEGRATED_UART @@ -24,6 +25,8 @@ config BOARD_SPECIFIC_OPTIONS select VBOOT if BOARD_FACEBOOK_WATSON_V2 select VBOOT_MEASURED_BOOT if BOARD_FACEBOOK_WATSON_V2 select VBOOT_STARTS_IN_ROMSTAGE if BOARD_FACEBOOK_WATSON_V2 + select VPD + select VPD_SMBIOS_VERSION config MAINBOARD_DIR string From fabe8f5a9552c789f7b0cee3caaa72b20c06f6ac Mon Sep 17 00:00:00 2001 From: Morgan Jang Date: Tue, 26 Nov 2019 11:32:02 +0800 Subject: [PATCH 18/67] mb/ocp/monolake: Create SMBIOS type 16 for Monolake platform TEST=Use "dmidecode -t 16" in Linux to check if SMBIOS type 16 exists Change-Id: Ie057742112f14447b226d432417d9301d4aea958 Signed-off-by: Morgan Jang Reviewed-on: https://review.coreboot.org/c/coreboot/+/37233 Reviewed-by: Angel Pons Tested-by: build bot (Jenkins) --- src/mainboard/ocp/monolake/mainboard.c | 46 +++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/src/mainboard/ocp/monolake/mainboard.c b/src/mainboard/ocp/monolake/mainboard.c index 9a1c9953ab..5f3408ec77 100644 --- a/src/mainboard/ocp/monolake/mainboard.c +++ b/src/mainboard/ocp/monolake/mainboard.c @@ -31,8 +31,9 @@ /* Default countdown is 15 minutes. */ #define DEFAULT_COUNTDOWN 9000 #define FRU_DEVICE_ID 0 - static struct fru_info_str fru_strings; +#define MAX_IMC 1 +#define MAX_DIMM_SIZE_GB (32 * MiB) static void init_frb2_wdt(void) { @@ -63,6 +64,44 @@ static void init_frb2_wdt(void) } } +#if CONFIG(GENERATE_SMBIOS_TABLES) +static int write_smbios_type16(struct device *dev, int *handle, unsigned long *current) +{ + struct smbios_type16 *t = (struct smbios_type16 *)*current; + u32 maximum_capacity; + int len = sizeof(struct smbios_type16); + + printk(BIOS_INFO, "Creating SMBIOS tables type 16 (note, ECC information is hard-coded) ..."); + + memset(t, 0, sizeof(struct smbios_type16)); + t->type = SMBIOS_PHYS_MEMORY_ARRAY; + t->location = MEMORY_ARRAY_LOCATION_SYSTEM_BOARD; + t->use = MEMORY_ARRAY_USE_SYSTEM; + /* The ECC setting can`t be confirmed in FSP, so hardcode it. */ + t->memory_error_correction = MEMORY_ARRAY_ECC_SINGLE_BIT; + t->memory_error_information_handle = 0xFFFE; + t->number_of_memory_devices = CONFIG_DIMM_MAX / MAX_IMC; + + maximum_capacity = (u32)(CONFIG_DIMM_MAX * MAX_DIMM_SIZE_GB); + if (maximum_capacity >= 0x80000000) { + t->maximum_capacity = 0x80000000; + t->extended_maximum_capacity = maximum_capacity << 10; + } else { + t->maximum_capacity = (u32)maximum_capacity; + t->extended_maximum_capacity = 0; + } + + *current += len; + t->handle = *handle; + *handle += 1; + t->length = len - 2; + + printk(BIOS_INFO, "done\n"); + + return len; +} +#endif + /* * mainboard_enable is executed as first thing after enumerate_buses(). * This is the earliest point to add customization. @@ -79,7 +118,12 @@ static void mainboard_enable(struct device *dev) clear_ipmi_flags(&rsp); system_reset(); } + read_fru_areas(BMC_KCS_BASE, FRU_DEVICE_ID, 0, &fru_strings); + +#if (CONFIG(GENERATE_SMBIOS_TABLES)) + dev->ops->get_smbios_data = write_smbios_type16; +#endif } struct chip_operations mainboard_ops = { From b43431d58e047783783e190ba684de28b9222443 Mon Sep 17 00:00:00 2001 From: Nico Huber Date: Mon, 6 Jul 2020 21:14:02 +0200 Subject: [PATCH 19/67] mb/lenovo/t60: Fix override devicetrees Commit c1dc2d5e68 (mb/lenovo/t60: Switch to override tree) converted these boards to override trees, but some device nodes were missed. Said nodes are essential, as `chip` configuration data is always tied to device nodes. The resulting `static.c` contained multiple copies of the `chip` configuration structs, but the wrong ones were hooked up. The therefore missing configuration of the clockgen led to general instability, especially with SMP under Linux (probably due to the attempt to enter lower C states on an idle core). Passing `maxcpus=1` to the Linux kernel served as a workaround. Change-Id: I6c26d633d1860cf9a5415994444e75ae1c2e59ad Signed-off-by: Nico Huber Reviewed-on: https://review.coreboot.org/c/coreboot/+/43065 Reviewed-by: Arthur Heymans Tested-by: build bot (Jenkins) --- src/mainboard/lenovo/t60/variants/t60/overridetree.cb | 2 ++ src/mainboard/lenovo/t60/variants/z61t/overridetree.cb | 1 + 2 files changed, 3 insertions(+) diff --git a/src/mainboard/lenovo/t60/variants/t60/overridetree.cb b/src/mainboard/lenovo/t60/variants/t60/overridetree.cb index eee3a4d575..551fff3771 100644 --- a/src/mainboard/lenovo/t60/variants/t60/overridetree.cb +++ b/src/mainboard/lenovo/t60/variants/t60/overridetree.cb @@ -44,6 +44,7 @@ chip northbridge/intel/i945 register "has_bdc_detection" = "1" register "bdc_gpio_num" = "7" register "bdc_gpio_lvl" = "0" + device pnp ff.2 on end end chip superio/nsc/pc87384 device pnp 2e.2 off # Serial Port / IR @@ -62,6 +63,7 @@ chip northbridge/intel/i945 register "regs" = "{ 0x2e, 0xf7, 0x3c, 0x20, 0x01, 0x00, 0x1b, 0x01, 0x54, 0xff, 0xff, 0x07 }" + device i2c 69 on end end end end diff --git a/src/mainboard/lenovo/t60/variants/z61t/overridetree.cb b/src/mainboard/lenovo/t60/variants/z61t/overridetree.cb index d29df3b488..c372b18e38 100644 --- a/src/mainboard/lenovo/t60/variants/z61t/overridetree.cb +++ b/src/mainboard/lenovo/t60/variants/z61t/overridetree.cb @@ -57,6 +57,7 @@ chip northbridge/intel/i945 # vendor clockgen setup register "regs" = "{ 0x6d, 0xff, 0xff, 0x20, 0x41, 0x7f, 0x18, 0x00 }" + device i2c 69 on end end end end From ea7fde7070ca84e35a4a4cd141b688470fba09d0 Mon Sep 17 00:00:00 2001 From: Philipp Deppenwiese Date: Tue, 20 Nov 2018 14:22:15 +0100 Subject: [PATCH 20/67] security/intel/txt: Add Intel TXT support Add TXT ramstage driver: * Show startup errors * Check for TXT reset * Check for Secrets-in-memory * Add assembly for GETSEC instruction * Check platform state if GETSEC instruction is supported * Configure TXT memory regions * Lock TXT * Protect TSEG using DMA protected regions * Place SINIT ACM * Print information about ACMs Extend the `security_clear_dram_request()` function: * Clear all DRAM if secrets are in memory Add a config so that the code gets build-tested. Since BIOS and SINIT ACM binaries are not available, use the STM binary as a placeholder. Tested on OCP Wedge100s and Facebook Watson * Able to enter a Measured Launch Environment using SINIT ACM and TBOOT * Secrets in Memory bit is set on ungraceful shutdown * Memory is cleared after ungraceful shutdown Change-Id: Iaf4be7f016cc12d3971e1e1fe171e6665e44c284 Signed-off-by: Philipp Deppenwiese Reviewed-on: https://review.coreboot.org/c/coreboot/+/37016 Tested-by: build bot (Jenkins) Reviewed-by: Christian Walter (cherry picked from commit 5f9f77672d096a013094f3cad63cb138167dbf1b) Reviewed-on: https://review.coreboot.org/c/coreboot/+/42712 Reviewed-by: Angel Pons Reviewed-by: Jonathan Zhang --- .../config.purism_librem15_v4.txt_build_test | 8 + src/security/intel/txt/Kconfig | 28 +- src/security/intel/txt/Makefile.inc | 19 +- src/security/intel/txt/common.c | 421 ++++++++++++++++++ src/security/intel/txt/getsec.c | 117 +++++ src/security/intel/txt/getsec_enteraccs.S | 318 +++++++++++++ src/security/intel/txt/logging.c | 241 ++++++++++ src/security/intel/txt/ramstage.c | 382 ++++++++++++++++ src/security/intel/txt/txt.h | 27 ++ src/security/intel/txt/txt_getsec.h | 21 + src/security/intel/txt/txt_register.h | 267 +++++++++++ src/security/memory/memory.c | 6 +- 12 files changed, 1846 insertions(+), 9 deletions(-) create mode 100644 configs/config.purism_librem15_v4.txt_build_test create mode 100644 src/security/intel/txt/common.c create mode 100644 src/security/intel/txt/getsec.c create mode 100644 src/security/intel/txt/getsec_enteraccs.S create mode 100644 src/security/intel/txt/logging.c create mode 100644 src/security/intel/txt/ramstage.c create mode 100644 src/security/intel/txt/txt.h create mode 100644 src/security/intel/txt/txt_getsec.h create mode 100644 src/security/intel/txt/txt_register.h diff --git a/configs/config.purism_librem15_v4.txt_build_test b/configs/config.purism_librem15_v4.txt_build_test new file mode 100644 index 0000000000..f2de8bc59f --- /dev/null +++ b/configs/config.purism_librem15_v4.txt_build_test @@ -0,0 +1,8 @@ +# Not meant for actual use. Exercises Intel TXT code. Since BIOS +# and SINIT ACM blobs are missing, use something else as placeholder. +CONFIG_VENDOR_PURISM=y +CONFIG_BOARD_PURISM_LIBREM15_V4=y +CONFIG_INTEL_TXT=y +CONFIG_INTEL_TXT_BIOSACM_FILE="3rdparty/blobs/cpu/intel/stm/stm.bin" +CONFIG_INTEL_TXT_SINITACM_FILE="3rdparty/blobs/cpu/intel/stm/stm.bin" +CONFIG_INTEL_TXT_LOGGING=y diff --git a/src/security/intel/txt/Kconfig b/src/security/intel/txt/Kconfig index 97d24fd6c9..d828a9de13 100644 --- a/src/security/intel/txt/Kconfig +++ b/src/security/intel/txt/Kconfig @@ -33,7 +33,7 @@ config INTEL_TXT_BIOSACM_FILE default "3rdparty/blobs/soc/intel/fsp_broadwell_de/biosacm.bin" if SOC_INTEL_FSP_BROADWELL_DE default "3rdparty/blobs/soc/intel/skylake/biosacm.bin" if SOC_INTEL_COMMON_SKYLAKE_BASE help - Intel TXT BIOS ACM file. This file can be obtained by privileged + Intel TXT BIOS ACM file. This file can be obtained through privileged access to Intel resources. Or for some platforms found inside the blob repository. @@ -42,16 +42,34 @@ config INTEL_TXT_SINITACM_FILE default "3rdparty/blobs/soc/intel/fsp_broadwell_de/sinitacm.bin" if SOC_INTEL_FSP_BROADWELL_DE default "3rdparty/blobs/soc/intel/skylake/sinitacm.bin" if SOC_INTEL_COMMON_SKYLAKE_BASE help - Intel TXT SINIT ACM file. This file can be obtained by privileged + Intel TXT SINIT ACM file. This file can be obtained through privileged access to Intel resources. Or for some platforms found inside the blob repository. +config INTEL_TXT_LOGGING + bool "Enable verbose logging" + help + Print more TXT related debug output. + Use in pre-production environments only! + config INTEL_TXT_BIOSACM_ALIGNMENT hex - default 0x20000 # 128KB + default 0x20000 # 128 KiB help - Exceptions are Ivy- and Sandy Bridge with 64KB and Purely with 256KB - alignment size. Please overwrite it SoC specific. + Exceptions are Ivy and Sandy Bridge with 64 KiB and Purley with 256 KiB + alignment size. If necessary, override from platform-specific Kconfig. + +config INTEL_TXT_CBFS_BIOS_POLICY + string + default "txt_bios_policy.bin" + +config INTEL_TXT_CBFS_BIOS_ACM + string + default "txt_bios_acm.bin" + +config INTEL_TXT_CBFS_SINIT_ACM + string + default "txt_sinit_acm.bin" endmenu # Intel diff --git a/src/security/intel/txt/Makefile.inc b/src/security/intel/txt/Makefile.inc index 38eb65d69c..39c3ad1dff 100644 --- a/src/security/intel/txt/Makefile.inc +++ b/src/security/intel/txt/Makefile.inc @@ -1,5 +1,14 @@ ifeq ($(CONFIG_INTEL_TXT),y) +romstage-y += common.c +romstage-$(CONFIG_INTEL_TXT_LOGGING) += logging.c + +ramstage-y += common.c +ramstage-y += getsec.c +ramstage-y += getsec_enteraccs.S +ramstage-y += ramstage.c +ramstage-$(CONFIG_INTEL_TXT_LOGGING) += logging.c + cbfs-files-y += txt_bios_acm.bin txt_bios_acm.bin-file := $(CONFIG_INTEL_TXT_BIOSACM_FILE) txt_bios_acm.bin-type := raw @@ -13,6 +22,8 @@ txt_sinit_acm.bin-align := 0x10 txt_sinit_acm.bin-compression := lzma endif +ifeq ($(CONFIG_CPU_INTEL_FIRMWARE_INTERFACE_TABLE),y) + INTERMEDIATE+=add_acm_fit add_acm_fit: $(obj)/coreboot.pre $(IFITTOOL) $(IFITTOOL) -r COREBOOT -a -n txt_bios_acm.bin -t 2 -s $(CONFIG_CPU_INTEL_NUM_FIT_ENTRIES) -f $< @@ -26,7 +37,9 @@ ibb-files += bootblock INTERMEDIATE+=add_ibb_fit add_ibb_fit: $(obj)/coreboot.pre $(IFITTOOL) - $(foreach file, $(ibb-files), $(shell $(IFITTOOL) -f $< -a -n $(file) -t 7 -s $(CONFIG_CPU_INTEL_NUM_FIT_ENTRIES) \ - -r COREBOOT)) true + $(foreach file, $(ibb-files), $(shell $(IFITTOOL) -f $< -a -n $(file) -t 7 \ + -s $(CONFIG_CPU_INTEL_NUM_FIT_ENTRIES) -r COREBOOT)) true -endif +endif # CPU_INTEL_FIRMWARE_INTERFACE_TABLE + +endif # INTEL_TXT diff --git a/src/security/intel/txt/common.c b/src/security/intel/txt/common.c new file mode 100644 index 0000000000..32350b7e89 --- /dev/null +++ b/src/security/intel/txt/common.c @@ -0,0 +1,421 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "txt.h" +#include "txt_register.h" +#include "txt_getsec.h" + +/** + * Dump the ACM error status bits. + * + * @param acm_error The status register to dump + * @return -1 on error (register is not valid) + * 0 on error (Class > 0 and Major > 0) + * 1 on success (Class == 0 and Major == 0 and progress > 0) + */ +int intel_txt_log_acm_error(const uint32_t acm_error) +{ + if (!(acm_error & ACMERROR_TXT_VALID)) + return -1; + + const uint8_t type = (acm_error & ACMERROR_TXT_TYPE_CODE) + >> ACMERROR_TXT_TYPE_SHIFT; + + switch (type) { + case ACMERROR_TXT_AC_MODULE_TYPE_BIOS: + printk(BIOS_ERR, "BIOSACM"); + break; + case ACMERROR_TXT_AC_MODULE_TYPE_SINIT: + printk(BIOS_ERR, "SINIT"); + break; + default: + printk(BIOS_ERR, "ACM"); + break; + } + printk(BIOS_ERR, ": Error code valid\n"); + + if (acm_error & ACMERROR_TXT_EXTERNAL) + printk(BIOS_ERR, " Caused by: External\n"); + else + printk(BIOS_ERR, " Caused by: Processor\n"); + + const uint32_t class = (acm_error & ACMERROR_TXT_CLASS_CODE) + >> ACMERROR_TXT_CLASS_SHIFT; + const uint32_t major = (acm_error & ACMERROR_TXT_MAJOR_CODE) + >> ACMERROR_TXT_MAJOR_SHIFT; + const uint32_t minor = (acm_error & ACMERROR_TXT_MINOR_CODE) + >> ACMERROR_TXT_MINOR_SHIFT; + const uint32_t progress = (acm_error & ACMERROR_TXT_PROGRESS_CODE) + >> ACMERROR_TXT_PROGRESS_SHIFT; + + if (!minor) { + if (class == 0 && major == 0 && progress > 0) { + printk(BIOS_ERR, " Execution successful\n"); + printk(BIOS_ERR, " Progress code 0x%x\n", progress); + } else { + printk(BIOS_ERR, " Error Class: %x\n", class); + printk(BIOS_ERR, " Error: %x.%x\n", major, progress); + } + } else { + printk(BIOS_ERR, " ACM didn't start\n"); + printk(BIOS_ERR, " Error Type: 0x%x\n", acm_error & 0xffffff); + return -1; + } + + return (acm_error & ACMERROR_TXT_EXTERNAL) && class == 0 && major == 0 && progress > 0; +} + +void intel_txt_log_spad(void) +{ + const uint64_t acm_status = read64((void *)TXT_SPAD); + + printk(BIOS_INFO, "TXT-STS: ACM verification "); + + if (acm_status & ACMSTS_VERIFICATION_ERROR) + printk(BIOS_INFO, "error\n"); + else + printk(BIOS_INFO, "successful\n"); + + printk(BIOS_INFO, "TXT-STS: IBB "); + + if (acm_status & ACMSTS_IBB_MEASURED) + printk(BIOS_INFO, "measured\n"); + else + printk(BIOS_INFO, "not measured\n"); + + printk(BIOS_INFO, "TXT-STS: TXT is "); + + if (acm_status & ACMSTS_TXT_DISABLED) + printk(BIOS_INFO, "disabled\n"); + else + printk(BIOS_INFO, "not disabled\n"); + + printk(BIOS_INFO, "TXT-STS: BIOS is "); + + if (acm_status & ACMSTS_BIOS_TRUSTED) + printk(BIOS_INFO, "trusted\n"); + else + printk(BIOS_INFO, "not trusted\n"); +} + +/* Returns true if secrets might be in memory */ +bool intel_txt_memory_has_secrets(void) +{ + bool ret; + if (!CONFIG(INTEL_TXT)) + return false; + + ret = (read8((void *)TXT_ESTS) & TXT_ESTS_WAKE_ERROR_STS) || + (read64((void *)TXT_E2STS) & TXT_E2STS_SECRET_STS); + + if (ret) + printk(BIOS_CRIT, "TXT-STS: Secrets in memory!\n"); + return ret; +} + +static struct acm_info_table *find_info_table(const void *ptr) +{ + const struct acm_header_v0 *acm_header = (struct acm_header_v0 *)ptr; + + return (struct acm_info_table *)(ptr + + (acm_header->header_len + acm_header->scratch_size) * sizeof(uint32_t)); +} + +/** + * Validate that the provided ACM is useable on this platform. + */ +static int validate_acm(const void *ptr) +{ + const struct acm_header_v0 *acm_header = (struct acm_header_v0 *)ptr; + uint32_t max_size_acm_area = 0; + + if (acm_header->module_type != CHIPSET_ACM) + return ACM_E_TYPE_NOT_MATCH; + + /* Seems inconsistent across generations. */ + if (acm_header->module_sub_type != 0 && acm_header->module_sub_type != 1) + return ACM_E_MODULE_SUB_TYPE_WRONG; + + if (acm_header->module_vendor != INTEL_ACM_VENDOR) + return ACM_E_MODULE_VENDOR_NOT_INTEL; + + if (((acm_header->header_len + acm_header->scratch_size) * sizeof(uint32_t) + + sizeof(struct acm_info_table)) > (acm_header->size & 0xffffff) * sizeof(uint32_t)) { + return ACM_E_SIZE_INCORRECT; + } + + if (!getsec_parameter(NULL, NULL, &max_size_acm_area, NULL, NULL, NULL)) + return ACM_E_CANT_CALL_GETSEC; + + /* + * Causes #GP if acm_header->size > processor internal authenticated + * code area capacity. + * SAFER MODE EXTENSIONS REFERENCE. + * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D + */ + const size_t acm_len = 1UL << log2_ceil((acm_header->size & 0xffffff) << 2); + if (max_size_acm_area < acm_len) { + printk(BIOS_ERR, "TEE-TXT: BIOS ACM doesn't fit into AC execution region\n"); + return ACM_E_NOT_FIT_INTO_CPU_ACM_MEM; + } + + struct acm_info_table *info = find_info_table(ptr); + if (!info) + return ACM_E_NO_INFO_TABLE; + if (info->chipset_acm_type != BIOS) + return ACM_E_NOT_BIOS_ACM; + + static const u8 acm_uuid[] = { + 0xaa, 0x3a, 0xc0, 0x7f, 0xa7, 0x46, 0xdb, 0x18, + 0x2e, 0xac, 0x69, 0x8f, 0x8d, 0x41, 0x7f, 0x5a, + }; + if (memcmp(acm_uuid, info->uuid, sizeof(acm_uuid)) != 0) + return ACM_E_UUID_NOT_MATCH; + + if ((acm_header->flags & ACM_FORMAT_FLAGS_DEBUG) == + (read64((void *)TXT_VER_FSBIF) & TXT_VER_PRODUCTION_FUSED)) + return ACM_E_PLATFORM_IS_NOT_PROD; + + return 0; +} + +/* + * Test all bits for TXT execution. + * + * @return 0 on success + */ +int intel_txt_run_bios_acm(const u8 input_params) +{ + struct cbfsf file; + void *acm_data; + struct region_device acm; + size_t acm_len; + int ret; + + if (cbfs_boot_locate(&file, CONFIG_INTEL_TXT_CBFS_BIOS_ACM, NULL)) { + printk(BIOS_ERR, "TEE-TXT: Couldn't locate BIOS ACM in CBFS.\n"); + return -1; + } + + cbfs_file_data(&acm, &file); + acm_data = rdev_mmap_full(&acm); + acm_len = region_device_sz(&acm); + if (!acm_data || acm_len == 0) { + printk(BIOS_ERR, "TEE-TXT: Couldn't map BIOS ACM from CBFS.\n"); + return -1; + } + + /* + * CPU enforces only 4KiB alignment. + * Chapter A.1.1 + * Intel TXT Software Development Guide (Document: 315168-015) + */ + if (!IS_ALIGNED((uintptr_t)acm_data, 4096)) { + printk(BIOS_ERR, "TEE-TXT: BIOS ACM isn't mapped at page boundary.\n"); + rdev_munmap(&acm, acm_data); + return -1; + } + + /* + * Causes #GP if not multiple of 64. + * SAFER MODE EXTENSIONS REFERENCE. + * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D + */ + if (!IS_ALIGNED(acm_len, 64)) { + printk(BIOS_ERR, "TEE-TXT: BIOS ACM size isn't multiple of 64.\n"); + rdev_munmap(&acm, acm_data); + return -1; + } + + /* + * The ACM should be aligned to it's size, but that's not possible, as + * some ACMs are not power of two. Use the next power of two for verification. + */ + if (!IS_ALIGNED((uintptr_t)acm_data, (1UL << log2_ceil(acm_len)))) { + printk(BIOS_ERR, "TEE-TXT: BIOS ACM isn't aligned to its size.\n"); + rdev_munmap(&acm, acm_data); + return -1; + } + + if (CONFIG(INTEL_TXT_LOGGING)) + txt_dump_acm_info(acm_data); + + ret = validate_acm(acm_data); + if (ret < 0) { + printk(BIOS_ERR, "TEE-TXT: Validation of ACM failed with: %d\n", ret); + rdev_munmap(&acm, acm_data); + return ret; + } + + /* Call into assembly which invokes the referenced ACM */ + getsec_enteraccs(input_params, (uintptr_t)acm_data, acm_len); + + rdev_munmap(&acm, acm_data); + + const uint64_t acm_status = read64((void *)TXT_SPAD); + if (acm_status & ACMERROR_TXT_VALID) { + printk(BIOS_ERR, "TEE-TXT: FATAL ACM launch error !\n"); + /* + * WARNING ! + * To clear TXT.BIOSACM.ERRORCODE you must issue a cold reboot! + */ + intel_txt_log_acm_error(read32((void *)TXT_BIOSACM_ERRORCODE)); + return -1; + } + if (intel_txt_log_acm_error(read32((void *)TXT_BIOSACM_ERRORCODE)) != 1) + return -1; + + return 0; +} + + /* Returns true if cond is not met */ +static bool check_precondition(const int cond) +{ + printk(BIOS_DEBUG, "%s\n", cond ? "true" : "false"); + return !cond; +} + +/* + * Test all bits that are required for Intel TXT. + * Enable SMX if available. + * + * @return 0 on success + */ +bool intel_txt_prepare_txt_env(void) +{ + bool failure = false; + uint32_t txt_feature_flags = 0; + + unsigned int ecx = cpuid_ecx(1); + + printk(BIOS_DEBUG, "TEE-TXT: CPU supports SMX: "); + failure |= check_precondition(ecx & CPUID_SMX); + + printk(BIOS_DEBUG, "TEE-TXT: CPU supports VMX: "); + failure |= check_precondition(ecx & CPUID_VMX); + + msr_t msr = rdmsr(IA32_FEATURE_CONTROL); + if (!(msr.lo & BIT(0))) { + printk(BIOS_ERR, "TEE-TXT: IA32_FEATURE_CONTROL is not locked\n"); + full_reset(); + } + + printk(BIOS_DEBUG, "TEE-TXT: IA32_FEATURE_CONTROL\n"); + printk(BIOS_DEBUG, " VMXON in SMX enable: "); + failure |= check_precondition(msr.lo & BIT(1)); + + printk(BIOS_DEBUG, " VMXON outside SMX enable: "); + failure |= check_precondition(msr.lo & FEATURE_ENABLE_VMX); + + printk(BIOS_DEBUG, " register is locked: "); + failure |= check_precondition(msr.lo & BIT(0)); + + /* IA32_FEATURE_CONTROL enables getsec instructions */ + printk(BIOS_DEBUG, " GETSEC (all instructions) is enabled: "); + failure |= check_precondition((msr.lo & 0xff00) == 0xff00); + + /* Prevent crash and opt out early */ + if (failure) + return true; + + uint32_t eax = 0; + /* + * GetSec[CAPABILITIES] + * SAFER MODE EXTENSIONS REFERENCE. + * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D + * Must check BIT0 of TXT chipset has been detected by CPU. + */ + if (!getsec_capabilities(&eax)) + return true; + + printk(BIOS_DEBUG, "TEE-TXT: GETSEC[CAPABILITIES] returned:\n"); + printk(BIOS_DEBUG, " TXT capable chipset: %s\n", (eax & BIT(0)) ? "true" : "false"); + + printk(BIOS_DEBUG, " ENTERACCS available: %s\n", (eax & BIT(2)) ? "true" : "false"); + printk(BIOS_DEBUG, " EXITAC available: %s\n", (eax & BIT(3)) ? "true" : "false"); + printk(BIOS_DEBUG, " SENTER available: %s\n", (eax & BIT(4)) ? "true" : "false"); + printk(BIOS_DEBUG, " SEXIT available: %s\n", (eax & BIT(5)) ? "true" : "false"); + printk(BIOS_DEBUG, " PARAMETERS available: %s\n", (eax & BIT(6)) ? "true" : "false"); + + /* + * Causes #GP if function is not supported by getsec. + * SAFER MODE EXTENSIONS REFERENCE. + * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D + * Order Number: 325383-060US + */ + if ((eax & 0x7d) != 0x7d) + failure = true; + + const uint64_t status = read64((void *)TXT_SPAD); + + if (status & ACMSTS_TXT_DISABLED) { + printk(BIOS_INFO, "TEE-TXT: TXT disabled by BIOS policy in FIT.\n"); + failure = true; + } + + /* + * Only the BSP must call getsec[ENTERACCS]. + * SAFER MODE EXTENSIONS REFERENCE. + * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D + * Order Number: 325383-060US + */ + if (!boot_cpu()) { + printk(BIOS_ERR, "TEE-TXT: BSP flag not set in APICBASE_MSR.\n"); + failure = true; + } + + /* + * There must be no MCEs pending. + * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D + * Order Number: 325383-060US + */ + msr = rdmsr(IA32_MCG_STATUS); + if (msr.lo & 0x4) { + printk(BIOS_ERR, "TEE-TXT: IA32_MCG_STATUS.MCIP is set.\n"); + failure = true; + } + + if (!getsec_parameter(NULL, NULL, NULL, NULL, NULL, &txt_feature_flags)) { + return true; + } else { + printk(BIOS_DEBUG, "TEE-TXT: Machine Check Register: "); + if (txt_feature_flags & GETSEC_PARAMS_TXT_EXT_MACHINE_CHECK) + printk(BIOS_DEBUG, "preserved\n"); + else + printk(BIOS_DEBUG, "must be clear\n"); + } + + if (!(txt_feature_flags & GETSEC_PARAMS_TXT_EXT_MACHINE_CHECK)) { + /* + * Make sure there are no uncorrectable MCE errors. + * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D + */ + msr = rdmsr(IA32_MCG_CAP); + size_t max_mc_msr = msr.lo & MCA_BANKS_MASK; + for (size_t i = 0; i < max_mc_msr; i++) { + msr = rdmsr(IA32_MC0_STATUS + 4 * i); + if (!(msr.hi & MCA_STATUS_HI_UC)) + continue; + + printk(BIOS_ERR, "TEE-TXT: IA32_MC%zd_STATUS.UC is set.\n", i); + failure = true; + break; + } + } + + /* Need to park all APs. */ + if (CONFIG(PARALLEL_MP_AP_WORK)) + mp_park_aps(); + + return failure; +} diff --git a/src/security/intel/txt/getsec.c b/src/security/intel/txt/getsec.c new file mode 100644 index 0000000000..a42607dccc --- /dev/null +++ b/src/security/intel/txt/getsec.c @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include +#include +#include +#include +#include + +#include "txt_register.h" +#include "txt_getsec.h" + +/** + * Check for SMX support and enable it if possible. + * + * Returns false on error, true on success. + */ +static bool getsec_enabled(void) +{ + unsigned int ecx = cpuid_ecx(1); + /* + * Check if SMX and VMX is supported by CPU. + */ + if (!(ecx & CPUID_SMX) || !(ecx & CPUID_VMX)) + return false; + + /* + * Check if SMX, VMX and GetSec instructions haven't been disabled. + */ + msr_t msr = rdmsr(IA32_FEATURE_CONTROL); + if ((msr.lo & 0xff07) != 0xff07) + return false; + + /* + * Enable SMX. Required to execute GetSec instruction. + * Chapter 2.2.4.3 + * Intel TXT Software Development Guide (Document: 315168-015) + */ + write_cr4(read_cr4() | CR4_SMXE); + + return true; +} + +/** + * Get information as returned by getsec[PARAMETER]. + * Arguments can be set to NULL if not needed. + * + * Returns false on error, true on success. + */ +bool getsec_parameter(uint32_t *version_mask, + uint32_t *version_numbers_supported, + uint32_t *max_size_acm_area, + uint32_t *memory_type_mask, + uint32_t *senter_function_disable, + uint32_t *txt_feature_flags) +{ + uint32_t i, eax, ebx, ecx; + + if (!getsec_enabled()) + return false; + + /* + * SAFER MODE EXTENSIONS REFERENCE. + * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D + */ + for (i = 0; i < 0x1f; i++) { + /* Getsec[PARAMETERS] */ + asm volatile ("getsec\n" + : "=a" (eax), "=b" (ebx), "=c" (ecx) + : "a" (IA32_GETSEC_PARAMETERS), "b" (i) :); + switch (eax & 0x1f) { + case 0: /* NULL - Exit marker */ + return true; + case 1: /* Supported AC module versions */ + if (version_mask) + *version_mask = ebx; + if (version_numbers_supported) + *version_numbers_supported = ecx; + break; + case 2: /* Max size of authenticated code execution area */ + if (max_size_acm_area) + *max_size_acm_area = eax & ~0x1f; + break; + case 3: /* External memory types supported during AC mode */ + if (memory_type_mask) + *memory_type_mask = eax; + break; + case 4: /* Selective SENTER functionality control */ + if (senter_function_disable) + *senter_function_disable = eax & (0x3f00); + break; + case 5: /* TXT extensions support */ + if (txt_feature_flags) + *txt_feature_flags = eax & (0x60); + break; + } + } + + return true; +} + +/** + * Get capabilities as returned by getsec[CAPABILITIES]. + * + * Returns false on error, true on success. + */ + +bool getsec_capabilities(uint32_t *eax) +{ + if (!getsec_enabled()) + return false; + + asm volatile ("getsec\n" + : "=a" (*eax) + : "a" (IA32_GETSEC_CAPABILITIES), "b" (0) :); + + return true; +} diff --git a/src/security/intel/txt/getsec_enteraccs.S b/src/security/intel/txt/getsec_enteraccs.S new file mode 100644 index 0000000000..3135de79b2 --- /dev/null +++ b/src/security/intel/txt/getsec_enteraccs.S @@ -0,0 +1,318 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include +#include +#include + +#define MTRR_HIGH_MASK $((1 << (CONFIG_CPU_ADDR_BITS - 32)) - 1) + +.macro PUSH_MSR x + movl $(\x), %ecx + rdmsr + push %eax + push %edx +.endm + +.macro POP_MSR x + movl $(\x), %ecx + pop %edx + pop %eax + wrmsr +.endm + +.macro CLEAR_MSR x + movl $(\x), %ecx + xorl %edx, %edx + xorl %eax, %eax + wrmsr +.endm + +.align 4 +.text + +/* + * See "SAFER MODE EXTENSIONS REFERENCE." + * Chapter "GETSEC[ENTERACCS] - Execute Authenticated Chipset Code" for reference. + * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D + * + * void getsec_enteraccs(uint32_t esi, + * uint32_t acm_base, + * uint32_t acm_size); + */ +.global getsec_enteraccs +getsec_enteraccs: + + /* Backup current register state */ + pushl %ebp + movl %esp, %ebp + + pushal + + movl %cr0, %eax + pushl %eax + movl %cr4, %eax + pushl %eax + + /* Pushed 10 32bit registers */ + + /* Reserve space on stack for GDT */ + subl $8, %esp + + PUSH_MSR IA32_MISC_ENABLE + PUSH_MSR MTRR_FIX_64K_00000 + PUSH_MSR MTRR_FIX_16K_80000 + PUSH_MSR MTRR_FIX_16K_A0000 + PUSH_MSR MTRR_FIX_4K_C0000 + PUSH_MSR MTRR_FIX_4K_C8000 + PUSH_MSR MTRR_FIX_4K_D0000 + PUSH_MSR MTRR_FIX_4K_D8000 + PUSH_MSR MTRR_FIX_4K_E0000 + PUSH_MSR MTRR_FIX_4K_F0000 + PUSH_MSR MTRR_FIX_4K_F8000 + + /* Push variable MTRRs in ascending order */ + + xorl %ebx, %ebx + jmp cond_push_var_mtrrs + +body_push_var_mtrrs: + + movl %ebx, %ecx + shll %ecx + addl $(MTRR_PHYS_BASE(0)), %ecx + rdmsr + push %eax + push %edx + incl %ecx /* MTRR_PHYS_MASK */ + rdmsr + push %eax + push %edx + + incl %ebx + +cond_push_var_mtrrs: + + movl $(MTRR_CAP_MSR), %ecx + rdmsr + andl $(0xff), %eax + cmp %ebx, %eax + jg body_push_var_mtrrs + + /* + * Disable cache. + * Chapter 2.2.4.3 + * Intel TXT Software Development Guide (Document: 315168-015) + */ + movl %cr0, %eax + orl $(CR0_CD | CR0_NW), %eax + movl %eax, %cr0 + + /* Disable fixed MTRRs */ + movl $(MTRR_DEF_TYPE_MSR), %ecx + rdmsr + andl $(~MTRR_DEF_TYPE_FIX_EN), %eax + wrmsr + + /* + * Clear fixed MTRRs. + * Chapter 2.2.5.1 + * Intel TXT Software Development Guide (Document: 315168-015) + */ + CLEAR_MSR MTRR_FIX_64K_00000 + CLEAR_MSR MTRR_FIX_16K_80000 + CLEAR_MSR MTRR_FIX_16K_A0000 + CLEAR_MSR MTRR_FIX_4K_C0000 + CLEAR_MSR MTRR_FIX_4K_C8000 + CLEAR_MSR MTRR_FIX_4K_D0000 + CLEAR_MSR MTRR_FIX_4K_D8000 + CLEAR_MSR MTRR_FIX_4K_E0000 + CLEAR_MSR MTRR_FIX_4K_F0000 + CLEAR_MSR MTRR_FIX_4K_F8000 + + /* + * Clear variable MTRRs + * Chapter 2.2.5.1 + * Intel TXT Software Development Guide (Document: 315168-015) + */ + movl $(MTRR_CAP_MSR), %ecx + rdmsr + andl $(0xff), %eax + movl %eax, %ebx + + xorl %eax, %eax + xorl %edx, %edx + + jmp cond_clear_var_mtrrs + +body_clear_var_mtrrs: + + decl %ebx + movl %ebx, %ecx + shll %ecx + addl $(MTRR_PHYS_BASE(0)), %ecx + wrmsr + incl %ecx /* MTRR_PHYS_MASK */ + wrmsr + +cond_clear_var_mtrrs: + + cmpl $0, %ebx + jnz body_clear_var_mtrrs + + /* + * Setup BIOS ACM as WB + * Chapter A.1.1 + * Intel TXT Software Development Guide (Document: 315168-015) + */ + movl $(MTRR_PHYS_BASE(0)), %ecx + movl 12(%ebp), %eax /* %eax = acmbase */ + orl $(6), %eax /* MTRR_TYPE_WB */ + movl $0, %edx + wrmsr + + /* Round acmsize to next power of two. Required for MTRR programming. */ + movl $1, %ebx + movl 16(%ebp), %ecx /* %ebx = acmsize */ + dec %ecx + bsr %ecx, %ecx /* find MSB */ + inc %ecx + shl %cl, %ebx + movl $(MTRR_PHYS_MASK(0)), %ecx + xorl %eax, %eax + subl %ebx, %eax /* %eax = 4GIB - log2_ceil(ACM SIZE) */ + orl $((1 << 11)), %eax /* MTRR_PHYS_MASK_VALID */ + movl MTRR_HIGH_MASK, %edx + wrmsr + + /* Enable cache - GPF# if not done */ + movl %cr0, %eax + andl $(~(CR0_CD | CR0_NW)), %eax + movl %eax, %cr0 + + /* Enable Numeric error - GPE# if not done */ + movl %cr0, %eax + orl $(CR0_NE), %eax + movl %eax, %cr0 + + /* Enable SMX and FXSTORE - for getsec */ + movl %cr4, %eax + orl $(CR4_SMXE | CR4_OSFXSR), %eax + movl %eax, %cr4 + + /* + * Save GDT + * Chapter A.1.2 + * Intel TXT Software Development Guide (Document: 315168-015) + */ + sgdt -48(%ebp) + + /* Backup stack pointer */ + movd %esp, %xmm0 + movd %ebp, %xmm1 + + /* + * Get function arguments. + * It's important to pass the exact ACM size as it's used by getsec to verify + * the integrity of ACM. Unlike the size for MTRR programming, which needs to + * be power of two. + * + * The following assembly code is based on tboot's tboot/include/txt/smx.h. + */ + movl 8(%ebp), %esi /* flags */ + movl 12(%ebp), %ebx /* acm_base */ + movl 16(%ebp), %ecx /* acm_size */ + + movl $0, %edx /* reserved, must be zero */ + movl $0, %edi /* must be zero */ + movl $2, %eax /* GetSec[ENTERACCS] */ + + getsec + + /* Restore stack pointer */ + movd %xmm0, %esp + movd %xmm1, %ebp + + /* Reload GDT */ + lgdt -48(%ebp) + + /* Set cs */ + ljmp $0x10, $1f +1: + /* Fix segment registers */ + movl $0x18, %eax + movl %eax, %ds + movl %eax, %es + movl %eax, %ss + movl %eax, %fs + movl %eax, %gs + + /* Disable cache */ + movl %cr0, %eax + orl $(CR0_CD | CR0_NW), %eax + movl %eax, %cr0 + + /* Pop variable MTRRs in descending order */ + + movl $(MTRR_CAP_MSR), %ecx + rdmsr + andl $(0xff), %eax + movl %eax, %ebx + + jmp cond_pop_var_mtrrs + +body_pop_var_mtrrs: + + decl %ebx + movl %ebx, %ecx + shll %ecx + addl $(MTRR_PHYS_MASK(0)), %ecx + pop %edx + pop %eax + wrmsr + decl %ecx /* MTRR_PHYS_BASE */ + pop %edx + pop %eax + wrmsr + +cond_pop_var_mtrrs: + + cmpl $0, %ebx + jne body_pop_var_mtrrs + + POP_MSR MTRR_FIX_4K_F8000 + POP_MSR MTRR_FIX_4K_F0000 + POP_MSR MTRR_FIX_4K_E0000 + POP_MSR MTRR_FIX_4K_D8000 + POP_MSR MTRR_FIX_4K_D0000 + POP_MSR MTRR_FIX_4K_C8000 + POP_MSR MTRR_FIX_4K_C0000 + POP_MSR MTRR_FIX_16K_A0000 + POP_MSR MTRR_FIX_16K_80000 + POP_MSR MTRR_FIX_64K_00000 + POP_MSR IA32_MISC_ENABLE + + /* Enable fixed MTRRs */ + movl $(MTRR_DEF_TYPE_MSR), %ecx + rdmsr + orl $(MTRR_DEF_TYPE_FIX_EN), %eax + wrmsr + + /* Enable cache */ + movl %cr0, %eax + andl $(~(CR0_CD | CR0_NW)), %eax + movl %eax, %cr0 + + /* Pop GDT */ + addl $8, %esp + + popl %eax + movl %eax, %cr4 + popl %eax + movl %eax, %cr0 + + popal + + movl %ebp, %esp + popl %ebp + + ret diff --git a/src/security/intel/txt/logging.c b/src/security/intel/txt/logging.c new file mode 100644 index 0000000000..cf14b55df9 --- /dev/null +++ b/src/security/intel/txt/logging.c @@ -0,0 +1,241 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include +#if CONFIG(SOC_INTEL_COMMON_BLOCK_SA) +#include +#endif + +#include +#include + +#include "txt.h" +#include "txt_register.h" + +/** + * Logs microcode or SINIT ACM errors. + * Does not log SBIOS ACM errors. + */ +static void log_txt_error(const char *phase) +{ + const uint64_t txt_error = read64((void *)TXT_ERROR); + + if (txt_error & ACMERROR_TXT_VALID) { + printk(BIOS_ERR, "%s: Error occurred\n", phase); + + if (txt_error & ACMERROR_TXT_EXTERNAL) + printk(BIOS_ERR, " Caused by: External\n"); + else + printk(BIOS_ERR, " Caused by: Processor\n"); + + printk(BIOS_ERR, " Type: "); + + switch (txt_error & TXT_ERROR_MASK) { + case 0: + printk(BIOS_ERR, "Legacy Shutdown\n"); + break; + case 5: + printk(BIOS_ERR, "Load memory type error in ACM area\n"); + break; + case 6: + printk(BIOS_ERR, "Unrecognized ACM format\n"); + break; + case 7: + printk(BIOS_ERR, "Failure to authenticate\n"); + break; + case 8: + printk(BIOS_ERR, "Invalid ACM format\n"); + break; + case 9: + printk(BIOS_ERR, "Unexpected Snoop hit\n"); + break; + case 10: + printk(BIOS_ERR, "Invalid event\n"); + break; + case 11: + printk(BIOS_ERR, "Invalid MLE\n"); + break; + case 12: + printk(BIOS_ERR, "Machine check event\n"); + break; + case 13: + printk(BIOS_ERR, "VMXAbort\n"); + break; + case 14: + printk(BIOS_ERR, "AC memory corruption\n"); + break; + case 15: + printk(BIOS_ERR, "Illegal voltage/bus ratio\n"); + break; + default: + printk(BIOS_ERR, "unknown\n"); + break; + } + } +} + +/** + * Dump useful informaation about the BIOS ACM state. + * Should run right after console_init() in romstage. + * Resets the platform if TXT reset is active and MLE cannot be established. + **/ +void intel_txt_log_bios_acm_error(void) +{ + uint32_t bios_acm_error; + uint64_t acm_status; + uint64_t txt_error; + + printk(BIOS_INFO, "TEE-TXT: State of ACM and ucode update:\n"); + + bios_acm_error = read32((void *)TXT_BIOSACM_ERRORCODE); + acm_status = read64((void *)TXT_SPAD); + txt_error = read64((void *)TXT_ERROR); + + /* Errors by BIOS ACM or FIT */ + if ((txt_error & ACMERROR_TXT_VALID) && + (acm_status & ACMERROR_TXT_VALID)) { + intel_txt_log_acm_error(read32((void *)TXT_BIOSACM_ERRORCODE)); + log_txt_error("FIT MICROCODE"); + } + /* Errors by SINIT */ + if ((txt_error & ACMERROR_TXT_VALID) && + !(acm_status & ACMERROR_TXT_VALID)) { + intel_txt_log_acm_error(txt_error); + log_txt_error("SINIT"); + } + + /* Check for fatal ACM error and TXT reset */ + uint8_t error = read8((void *)TXT_ESTS); + if (error & TXT_ESTS_TXT_RESET_STS) { + printk(BIOS_CRIT, "TXT-STS: Intel TXT reset detected\n"); + intel_txt_log_acm_error(read32((void *)TXT_ERROR)); + } +} + +/** + * Dump information about the provided ACM. + */ +void txt_dump_acm_info(const struct acm_header_v0 *acm_header) +{ + const struct acm_info_table *info = NULL; + if (!acm_header) + return; + + printk(BIOS_INFO, "ACM @ %p\n", acm_header); + + const size_t acm_size = (acm_header->size & 0xffffff) << 2; + const size_t info_off = (acm_header->header_len + acm_header->scratch_size) * 4; + + if (acm_size > (info_off + sizeof(struct acm_info_table))) + info = (const struct acm_info_table *) + ((const unsigned char *)acm_header + info_off); + + printk(BIOS_INFO, " ACM: Binary Info\n"); + if (acm_header->module_type == CHIPSET_ACM) + printk(BIOS_INFO, " Type: Chipset ACM\n"); + + if (acm_header->module_sub_type == 0) + printk(BIOS_INFO, " Subtype: undefined\n"); + else if (acm_header->module_sub_type == 1) + printk(BIOS_INFO, " Subtype: Run at reset\n"); + + printk(BIOS_INFO, " Header: v%u.%u\n", acm_header->header_version[0], + acm_header->header_version[1]); + + printk(BIOS_INFO, " Chipset: %u\n", acm_header->chipset_id); + printk(BIOS_INFO, " Size: %zu\n", acm_size); + + switch (acm_header->flags) { + case ACM_FORMAT_FLAGS_PW: + printk(BIOS_INFO, " Flags: PW signed (Production Worthy)\n"); + break; + case ACM_FORMAT_FLAGS_NPW: + printk(BIOS_INFO, " Flags: NPW signed (Non Production Worthy)\n"); + break; + case ACM_FORMAT_FLAGS_DEBUG: + printk(BIOS_INFO, " Flags: Debug signed\n"); + break; + } + + if (acm_header->module_vendor == INTEL_ACM_VENDOR) + printk(BIOS_INFO, " Vendor: Intel Corporation\n"); + + printk(BIOS_INFO, " Date: %x\n", acm_header->date); + + switch (acm_header->size) { + case ACM_FORMAT_SIZE_64KB: + printk(BIOS_INFO, " Size: 64KB\n"); + printk(BIOS_INFO, " CBnT: no\n"); + break; + case ACM_FORMAT_SIZE_128KB: + printk(BIOS_INFO, " Size: 128KB\n"); + printk(BIOS_INFO, " CBnT: no\n"); + break; + case ACM_FORMAT_SIZE_256KB: + printk(BIOS_INFO, " Size: 256KB\n"); + printk(BIOS_INFO, " CBnT: yes\n"); + break; + default: + printk(BIOS_INFO, " Size: 0x%08x\n", acm_header->size); + + break; + } + + printk(BIOS_INFO, " TXT SVN: %u\n", acm_header->txt_svn); + printk(BIOS_INFO, " SE SVN: %u\n", acm_header->se_svn); + + if (!info) + return; + printk(BIOS_INFO, " Table info:\n"); + printk(BIOS_INFO, " UUID: "); + for (size_t i = 0; i < sizeof(info->uuid); i++) + printk(BIOS_INFO, "%02X ", info->uuid[i]); + printk(BIOS_INFO, "\n"); + printk(BIOS_INFO, " Chipset acm type: 0x%x\n", info->chipset_acm_type); + printk(BIOS_INFO, " Capabilities: 0x%x\n", info->capabilities); +} + +/** + * Dump information about the chipset's TXT capabilities. + */ +void txt_dump_chipset_info(void) +{ + printk(BIOS_INFO, "TEE-TXT: Chipset Key Hash 0x"); + for (int i = 0; i < TXT_ACM_KEY_HASH_LEN; i++) { + printk(BIOS_INFO, "%llx", read64((void *)TXT_ACM_KEY_HASH + + (i * sizeof(uint64_t)))); + } + printk(BIOS_INFO, "\n"); + + printk(BIOS_INFO, "TEE-TXT: DIDVID 0x%x\n", read32((void *)TXT_DIDVID)); + printk(BIOS_INFO, "TEE-TXT: production fused chipset: %s\n", + (read64((void *)TXT_VER_FSBIF) & TXT_VER_PRODUCTION_FUSED) ? "true" : "false"); +} + +void txt_dump_regions(void) +{ + struct txt_biosdataregion *bdr = NULL; + uintptr_t tseg = 0; + uint64_t reg64; + + reg64 = read64((void *)TXT_HEAP_BASE); + if ((reg64 != 0 && reg64 != ~0UL) && + (read64((void *)(uintptr_t)reg64) >= (sizeof(*bdr) + sizeof(uint64_t)))) + bdr = (void *)((uintptr_t)reg64 + sizeof(uint64_t)); + + printk(BIOS_DEBUG, "TEE-TXT: TSEG 0x%lx\n", tseg * MiB); + printk(BIOS_DEBUG, "TEE-TXT: TXT.HEAP.BASE 0x%llx\n", read64((void *)TXT_HEAP_BASE)); + printk(BIOS_DEBUG, "TEE-TXT: TXT.HEAP.SIZE 0x%llx\n", read64((void *)TXT_HEAP_SIZE)); + printk(BIOS_DEBUG, "TEE-TXT: TXT.SINIT.BASE 0x%llx\n", read64((void *)TXT_SINIT_BASE)); + printk(BIOS_DEBUG, "TEE-TXT: TXT.SINIT.SIZE 0x%llx\n", read64((void *)TXT_SINIT_SIZE)); + printk(BIOS_DEBUG, "TEE-TXT: TXT.MSEG.BASE 0x%llx\n", read64((void *)TXT_MSEG_BASE)); + printk(BIOS_DEBUG, "TEE-TXT: TXT.MSEG.SIZE 0x%llx\n", read64((void *)TXT_MSEG_SIZE)); + + if (bdr) { + printk(BIOS_DEBUG, "TEE-TXT: BiosDataRegion.bios_sinit_size 0x%x\n", + bdr->bios_sinit_size); + printk(BIOS_DEBUG, "TEE-TXT: BiosDataRegion.lcp_pd_size 0x%llx\n", + bdr->lcp_pd_size); + printk(BIOS_DEBUG, "TEE-TXT: BiosDataRegion.lcp_pd_base 0x%llx\n", + bdr->lcp_pd_base); + } +} diff --git a/src/security/intel/txt/ramstage.c b/src/security/intel/txt/ramstage.c new file mode 100644 index 0000000000..76efa96ca8 --- /dev/null +++ b/src/security/intel/txt/ramstage.c @@ -0,0 +1,382 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#if CONFIG(SOC_INTEL_FSP_BROADWELL_DE) +#include +#include +#endif + +#include "txt.h" +#include "txt_register.h" +#include "txt_getsec.h" + +/* FIXME: Seems to work only on some platforms */ +static void log_ibb_measurements(void) +{ + const uint64_t mseg_size = read64((void *)TXT_MSEG_SIZE); + uint64_t mseg_base = read64((void *)TXT_MSEG_BASE); + + if (!mseg_size || !mseg_base || mseg_size <= mseg_base) + return; + /* + * MSEG SIZE and MSEG BASE might contain random values. + * Assume below 4GiB and 8byte aligned. + */ + if (mseg_base & ~0xfffffff8ULL || mseg_size & ~0xfffffff8ULL) + return; + + printk(BIOS_INFO, "TEE-TXT: IBB Hash 0x"); + for (; mseg_base < mseg_size; mseg_base++) + printk(BIOS_INFO, "%02X", read8((void *)(uintptr_t)mseg_base)); + + printk(BIOS_INFO, "\n"); +} + +void bootmem_platform_add_ranges(void) +{ + uint64_t status = read64((void *)TXT_SPAD); + + if (status & ACMSTS_TXT_DISABLED) + return; + + /* Chapter 5.5.5 Intel TXT reserved memory */ + bootmem_add_range(TXT_RESERVED_SPACE, + TXT_RESERVED_SPACE_SIZE, + BM_MEM_RESERVED); + + /* Intel TPM decode memory */ + bootmem_add_range(TXT_TPM_DECODE_AREA, + TXT_RESERVED_SPACE - TXT_TPM_DECODE_AREA, + BM_MEM_RESERVED); + + /* Intel TXT public space memory */ + bootmem_add_range(TXT_PUBLIC_SPACE, + TXT_TPM_DECODE_AREA - TXT_PUBLIC_SPACE, + BM_MEM_RESERVED); + + /* Intel TXT private space memory */ + bootmem_add_range(TXT_PRIVATE_SPACE, + TXT_PUBLIC_SPACE - TXT_PRIVATE_SPACE, + BM_MEM_RESERVED); + + const uint32_t txt_dev_memory = read32((void *)TXT_DPR) & + (TXT_DPR_TOP_ADDR_MASK << TXT_DPR_TOP_ADDR_SHIFT); + const uint32_t txt_dev_size = + (read32((void *)TXT_DPR) >> TXT_DPR_LOCK_SIZE_SHIFT) & + TXT_DPR_LOCK_SIZE_MASK; + + /* Chapter 5.5.6 Intel TXT Device Memory */ + bootmem_add_range(txt_dev_memory - txt_dev_size * MiB, + txt_dev_size * MiB, + BM_MEM_RESERVED); +} + +static bool get_wake_error_status(void) +{ + const uint8_t error = read8((void *)TXT_ESTS); + return !!(error & TXT_ESTS_WAKE_ERROR_STS); +} + +static void check_secrets_txt(void *unused) +{ + uint64_t status = read64((void *)TXT_SPAD); + + if (status & ACMSTS_TXT_DISABLED) + return; + + /* Check for fatal ACM error and TXT reset */ + if (get_wake_error_status()) { + /* + * Check if secrets bit needs to be reset. Only platforms that support + * CONFIG(PLATFORM_HAS_DRAM_CLEAR) will be able to run this code. + * Assume all memory really was cleared. + * + * TXT will issue a platform reset to come up sober. + */ + if (intel_txt_memory_has_secrets()) { + printk(BIOS_INFO, "TEE-TXT: Wiping TEE...\n"); + intel_txt_run_bios_acm(ACMINPUT_CLEAR_SECRETS); + + /* Should never reach this point ... */ + intel_txt_log_acm_error(read32((void *)TXT_BIOSACM_ERRORCODE)); + die("Waiting for platform reset...\n"); + } + } +} + +BOOT_STATE_INIT_ENTRY(BS_POST_DEVICE, BS_ON_ENTRY, check_secrets_txt, NULL); + +/** + * Log TXT startup errors, check all bits for TXT, run BIOSACM using + * GETSEC[ENTERACCS]. + * + * If a "TXT reset" is detected or "memory had secrets" is set, then do nothing as + * 1. Running ACMs will cause a TXT-RESET + * 2. Memory will be scrubbed in BS_DEV_INIT + * 3. TXT-RESET will be issued by code above later + * + */ +static void init_intel_txt(void *unused) +{ + const uint64_t status = read64((void *)TXT_SPAD); + + if (status & ACMSTS_TXT_DISABLED) + return; + + printk(BIOS_INFO, "TEE-TXT: Initializing TEE...\n"); + + intel_txt_log_spad(); + + if (CONFIG(INTEL_TXT_LOGGING)) { + intel_txt_log_bios_acm_error(); + txt_dump_chipset_info(); + } + + printk(BIOS_INFO, "TEE-TXT: Validate TEE...\n"); + + if (intel_txt_prepare_txt_env()) { + printk(BIOS_ERR, "TEE-TXT: Failed to prepare TXT environment\n"); + return; + } + + /* Check for fatal ACM error and TXT reset */ + if (get_wake_error_status()) { + /* Can't run ACMs with TXT_ESTS_WAKE_ERROR_STS set */ + printk(BIOS_ERR, "TEE-TXT: Fatal BIOS ACM error reported\n"); + return; + } + + printk(BIOS_INFO, "TEE-TXT: Testing BIOS ACM calling code...\n"); + + /* + * Test BIOS ACM code. + * ACM should do nothing on reserved functions, and return an error code + * in TXT_BIOSACM_ERRORCODE. Tests showed that this is not true. + * Use special function "NOP" that does 'nothing'. + */ + if (intel_txt_run_bios_acm(ACMINPUT_NOP) < 0) { + printk(BIOS_ERR, "TEE-TXT: Error calling BIOS ACM with NOP function.\n"); + return; + } + + if (status & (ACMSTS_BIOS_TRUSTED | ACMSTS_IBB_MEASURED)) { + log_ibb_measurements(); + + int s3resume = acpi_is_wakeup_s3(); + if (!s3resume) { + printk(BIOS_INFO, "TEE-TXT: Scheck...\n"); + if (intel_txt_run_bios_acm(ACMINPUT_SCHECK) < 0) { + printk(BIOS_ERR, "TEE-TXT: Error calling BIOS ACM.\n"); + return; + } + } + } +} + +BOOT_STATE_INIT_ENTRY(BS_DEV_INIT, BS_ON_EXIT, init_intel_txt, NULL); + +static void push_sinit_heap(u8 **heap_ptr, void *data, size_t data_length) +{ + /* Push size */ + const uint64_t tmp = data_length + 8; + memcpy(*heap_ptr, &tmp, 8); + *heap_ptr += 8; + + if (data_length) { + /* Push data */ + memcpy(*heap_ptr, data, data_length); + *heap_ptr += data_length; + } +} + +/** + * Finalize the TXT device. + * + * - Lock TXT register. + * - Protect TSEG using DMA protected regions. + * - Setup TXT regions. + * - Place SINIT ACM in TXT_SINIT memory segment. + * - Fill TXT BIOSDATA region. + */ +static void lockdown_intel_txt(void *unused) +{ + const uint64_t status = read64((void *)TXT_SPAD); + uintptr_t tseg = 0; + + if (status & ACMSTS_TXT_DISABLED) + return; + + printk(BIOS_INFO, "TEE-TXT: Locking TEE...\n"); + + /* Lock TXT config, unlocks TXT_HEAP_BASE */ + if (intel_txt_run_bios_acm(ACMINPUT_LOCK_CONFIG) < 0) { + printk(BIOS_ERR, "TEE-TXT: Failed to lock registers.\n"); + printk(BIOS_ERR, "TEE-TXT: SINIT won't be supported.\n"); + return; + } + + if (CONFIG(SOC_INTEL_FSP_BROADWELL_DE)) + tseg = sa_get_tseg_base() >> 20; + + /* + * Document Number: 558294 + * Chapter 5.5.6.1 DMA Protection Memory Region + */ + + const u8 dpr_capable = !!(read64((void *)TXT_CAPABILITIES) & + TXT_CAPABILITIES_DPR); + printk(BIOS_INFO, "TEE-TXT: DPR capable %x\n", dpr_capable); + if (dpr_capable) { + + /* Protect 3 MiB below TSEG and lock register */ + write64((void *)TXT_DPR, (TXT_DPR_TOP_ADDR(tseg) | + TXT_DPR_LOCK_SIZE(3) | + TXT_DPR_LOCK_MASK)); + +#if CONFIG(SOC_INTEL_FSP_BROADWELL_DE) + broadwell_de_set_dpr(tseg, 3 * MiB); + broadwell_de_lock_dpr(); +#endif + printk(BIOS_INFO, "TEE-TXT: TXT.DPR 0x%08x\n", + read32((void *)TXT_DPR)); + } + + /* + * Document Number: 558294 + * Chapter 5.5.6.3 Intel TXT Heap Memory Region + */ + write64((void *)TXT_HEAP_SIZE, 0xE0000); + write64((void *)TXT_HEAP_BASE, + ALIGN_DOWN((tseg * MiB) - read64((void *)TXT_HEAP_SIZE), 4096)); + + /* + * Document Number: 558294 + * Chapter 5.5.6.2 SINIT Memory Region + */ + write64((void *)TXT_SINIT_SIZE, 0x20000); + write64((void *)TXT_SINIT_BASE, + ALIGN_DOWN(read64((void *)TXT_HEAP_BASE) - + read64((void *)TXT_SINIT_SIZE), 4096)); + + /* + * BIOS Data Format + * Chapter C.2 + * Intel TXT Software Development Guide (Document: 315168-015) + */ + struct { + struct txt_biosdataregion bdr; + struct txt_heap_acm_element heap_acm; + struct txt_extended_data_element_header end; + } __packed data = {0}; + + /* TPM2.0 requires version 6 of BDT */ + if (CONFIG(TPM2)) + data.bdr.version = 6; + else + data.bdr.version = 5; + + data.bdr.no_logical_procs = dev_count_cpu(); + + void *sinit_base = (void *)(uintptr_t)read64((void *)TXT_SINIT_BASE); + data.bdr.bios_sinit_size = cbfs_boot_load_file(CONFIG_INTEL_TXT_CBFS_SINIT_ACM, + sinit_base, + read64((void *)TXT_SINIT_SIZE), + CBFS_TYPE_RAW); + + if (data.bdr.bios_sinit_size) { + printk(BIOS_INFO, "TEE-TXT: Placing SINIT ACM in memory.\n"); + if (CONFIG(INTEL_TXT_LOGGING)) + txt_dump_acm_info(sinit_base); + } else { + printk(BIOS_ERR, "TEE-TXT: Couldn't locate SINIT ACM in CBFS.\n"); + /* Clear memory */ + memset(sinit_base, 0, read64((void *)TXT_SINIT_SIZE)); + } + + struct cbfsf file; + /* The following have been removed from BIOS Data Table in version 6 */ + if (!cbfs_boot_locate(&file, CONFIG_INTEL_TXT_CBFS_BIOS_POLICY, NULL)) { + struct region_device policy; + + cbfs_file_data(&policy, &file); + void *policy_data = rdev_mmap_full(&policy); + size_t policy_len = region_device_sz(&policy); + + if (policy_data && policy_len) { + /* Point to FIT Type 9 entry in flash */ + data.bdr.lcp_pd_base = (uintptr_t)policy_data; + data.bdr.lcp_pd_size = (uint64_t)policy_len; + rdev_munmap(&policy, policy_data); + } else { + printk(BIOS_ERR, "TEE-TXT: Couldn't map LCP PD Policy from CBFS.\n"); + } + } else { + printk(BIOS_ERR, "TEE-TXT: Couldn't locate LCP PD Policy in CBFS.\n"); + } + + data.bdr.support_acpi_ppi = 0; + data.bdr.platform_type = 0; + + /* Extended elements - ACM addresses */ + data.heap_acm.header.type = HEAP_EXTDATA_TYPE_ACM; + data.heap_acm.header.size = sizeof(data.heap_acm); + if (data.bdr.bios_sinit_size) { + data.heap_acm.num_acms = 2; + data.heap_acm.acm_addrs[1] = (uintptr_t)sinit_base; + } else { + data.heap_acm.num_acms = 1; + } + data.heap_acm.acm_addrs[0] = + (uintptr_t)cbfs_boot_map_with_leak(CONFIG_INTEL_TXT_CBFS_BIOS_ACM, + CBFS_TYPE_RAW, + NULL); + /* Extended elements - End marker */ + data.end.type = HEAP_EXTDATA_TYPE_END; + data.end.size = sizeof(data.end); + + /* Fill TXT.HEAP.BASE with 4 subregions */ + u8 *heap_struct = (void *)((uintptr_t)read64((void *)TXT_HEAP_BASE)); + + /* BiosData */ + push_sinit_heap(&heap_struct, &data, sizeof(data)); + + /* OsMLEData */ + /* FIXME: Does firmware need to write this? */ + push_sinit_heap(&heap_struct, NULL, 0); + + /* OsSinitData */ + /* FIXME: Does firmware need to write this? */ + push_sinit_heap(&heap_struct, NULL, 0); + + /* SinitMLEData */ + /* FIXME: Does firmware need to write this? */ + push_sinit_heap(&heap_struct, NULL, 0); + + /* + * FIXME: Server-TXT capable platforms need to install an STM in SMM and set up MSEG. + */ + + /** + * Chapter 5.10.1 SMM in the Intel TXT for Servers Environment + * Disable MSEG. + */ + write64((void *)TXT_MSEG_SIZE, 0); + write64((void *)TXT_MSEG_BASE, 0); + + if (CONFIG(INTEL_TXT_LOGGING)) + txt_dump_regions(); +} + +BOOT_STATE_INIT_ENTRY(BS_POST_DEVICE, BS_ON_EXIT, lockdown_intel_txt, NULL); diff --git a/src/security/intel/txt/txt.h b/src/security/intel/txt/txt.h new file mode 100644 index 0000000000..fc5c49e67e --- /dev/null +++ b/src/security/intel/txt/txt.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef SECURITY_INTEL_TXT_H_ +#define SECURITY_INTEL_TXT_H_ + +#include + +/* Error codes */ +#define ACM_E_TYPE_NOT_MATCH 0x01 +#define ACM_E_MODULE_SUB_TYPE_WRONG 0x02 +#define ACM_E_MODULE_VENDOR_NOT_INTEL 0x03 +#define ACM_E_SIZE_INCORRECT 0x04 +#define ACM_E_CANT_CALL_GETSEC 0x05 +#define ACM_E_NOT_FIT_INTO_CPU_ACM_MEM 0x06 +#define ACM_E_NO_INFO_TABLE 0x07 +#define ACM_E_NOT_BIOS_ACM 0x08 +#define ACM_E_UUID_NOT_MATCH 0x09 +#define ACM_E_PLATFORM_IS_NOT_PROD 0x10 + +void intel_txt_log_bios_acm_error(void); +int intel_txt_log_acm_error(const uint32_t acm_error); +void intel_txt_log_spad(void); +bool intel_txt_memory_has_secrets(void); +int intel_txt_run_bios_acm(const u8 input_params); +bool intel_txt_prepare_txt_env(void); + +#endif /* SECURITY_INTEL_TXT_H_ */ diff --git a/src/security/intel/txt/txt_getsec.h b/src/security/intel/txt/txt_getsec.h new file mode 100644 index 0000000000..7c4a1a4283 --- /dev/null +++ b/src/security/intel/txt/txt_getsec.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef SECURITY_INTEL_TXT_GETSEC_H_ +#define SECURITY_INTEL_TXT_GETSEC_H_ + +#include + +bool getsec_parameter(uint32_t *version_mask, + uint32_t *version_numbers_supported, + uint32_t *max_size_acm_area, + uint32_t *memory_type_mask, + uint32_t *senter_function_disable, + uint32_t *txt_feature_flags); + +bool getsec_capabilities(uint32_t *eax); + +void getsec_enteraccs(const uint32_t esi, + const uint32_t acm_base, + const uint32_t acm_size); + +#endif /* SECURITY_INTEL_TXT_REGISTER_H_ */ diff --git a/src/security/intel/txt/txt_register.h b/src/security/intel/txt/txt_register.h new file mode 100644 index 0000000000..70bb309f15 --- /dev/null +++ b/src/security/intel/txt/txt_register.h @@ -0,0 +1,267 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef SECURITY_INTEL_TXT_REGISTER_H_ +#define SECURITY_INTEL_TXT_REGISTER_H_ + +#include +#include + +/* + * Document: 315168-016 + * Intel Trusted Execution Technology (Intel TXT) + * Software Development Guide + * Chapter B + */ +#define TXT_BASE 0xfed30000UL + +#define TXT_STS (TXT_BASE + 0) +#define TXT_ESTS (TXT_BASE + 8) +#define TXT_ESTS_TXT_RESET_STS (1 << 0) +/* + * Chapter 6 + * Intel Trusted Execution Technology Lab Handout + */ +#define TXT_ESTS_WAKE_ERROR_STS (1 << 6) + +#define TXT_ERROR (TXT_BASE + 0x30) +#define ACMERROR_TXT_VALID (1ul << 31) +#define ACMERROR_TXT_EXTERNAL (1ul << 30) + +#define ACMERROR_TXT_PROGRESS_SHIFT 16 +#define ACMERROR_TXT_MINOR_SHIFT 15 +#define ACMERROR_TXT_MAJOR_SHIFT 10 +#define ACMERROR_TXT_CLASS_SHIFT 4 +#define ACMERROR_TXT_TYPE_SHIFT 0 + +#define ACMERROR_TXT_PROGRESS_CODE (0xffull << ACMERROR_TXT_PROGRESS_SHIFT) +#define ACMERROR_TXT_MINOR_CODE (0x01ull << ACMERROR_TXT_MINOR_SHIFT) +#define ACMERROR_TXT_MAJOR_CODE (0x1full << ACMERROR_TXT_MAJOR_SHIFT) +#define ACMERROR_TXT_CLASS_CODE (0x3full << ACMERROR_TXT_CLASS_SHIFT) +#define ACMERROR_TXT_TYPE_CODE (0x0full << ACMERROR_TXT_TYPE_SHIFT) + +#define ACMERROR_TXT_AC_MODULE_TYPE_BIOS 0 +#define ACMERROR_TXT_AC_MODULE_TYPE_SINIT 1 + +#define TXT_ERROR_MASK (0x3ff << 0) + +#define TXT_CMD_RESET (TXT_BASE + 0x38) +#define TXT_CMD_CLOSE_PRIVATE (TXT_BASE + 0x48) + +/* Present in Document Number: 315168-016. */ +#define TXT_SPAD (TXT_BASE + 0xa0) +#define ACMSTS_IBB_MEASURED (1ull << 63) +#define ACMSTS_VERIFICATION_ERROR (1ull << 62) +#define ACMSTS_BG_STARTUP_ERROR (1ull << 61) /* CBnT platforms only */ +#define ACMSTS_TXT_DISABLED (1ull << 60) /* disabled by FIT type 0xA record */ +#define ACMSTS_BIOS_TRUSTED (1ull << 59) +#define ACMSTS_MEM_CLEAR_POWER_DOWN (1ull << 47) +#define ACMSTS_TXT_STARTUP_SUCCESS (1ull << 30) + +#define TXT_VER_FSBIF (TXT_BASE + 0x100) +#define TXT_VER_PRODUCTION_FUSED (1ull << 31) + +#define TXT_DIDVID (TXT_BASE + 0x110) + +/* + * Chapter 6 + * Intel Trusted Execution Technology Lab Handout + */ +#define TXT_CAPABILITIES (TXT_BASE + 0x200) +#define TXT_CAPABILITIES_DPR (1ull << 26) +#define TXT_CAPABILITIES_PMRC (1ull << 19) + +#define TXT_VER_QPIIF (TXT_BASE + 0x200) + +#define TXT_SINIT_BASE (TXT_BASE + 0x270) +#define TXT_SINIT_SIZE (TXT_BASE + 0x278) +#define TXT_MLE_JOIN (TXT_BASE + 0x290) + +#define TXT_HEAP_BASE (TXT_BASE + 0x300) +#define TXT_HEAP_SIZE (TXT_BASE + 0x308) +/* + * Chapter 6 + * Intel Trusted Execution Technology Lab Handout + */ +#define TXT_MSEG_BASE (TXT_BASE + 0x310) +#define TXT_MSEG_SIZE (TXT_BASE + 0x318) + +/* + * Chapter 5.4.2.1 + * Intel Trusted Execution Technology Lab Handout + */ +#define TXT_BIOSACM_ERRORCODE (TXT_BASE + 0x328) + +#define TXT_DPR (TXT_BASE + 0x330) +#define TXT_DPR_LOCK_SHIFT 0 +#define TXT_DPR_LOCK_SIZE_SHIFT 4 +#define TXT_DPR_LOCK_SIZE_MASK 0xff +#define TXT_DPR_TOP_ADDR_SHIFT 20 +#define TXT_DPR_TOP_ADDR_MASK 0xfff + +#define TXT_DPR_LOCK_MASK (1 << TXT_DPR_LOCK_SHIFT) +#define TXT_DPR_LOCK_SIZE(x) ((x) << TXT_DPR_LOCK_SIZE_SHIFT) +#define TXT_DPR_TOP_ADDR(x) ((x) << TXT_DPR_TOP_ADDR_SHIFT) + +#define TXT_ACM_KEY_HASH (TXT_BASE + 0x400) +#define TXT_ACM_KEY_HASH_LEN 0x4 + +#define TXT_E2STS (TXT_BASE + 0x8f0) +#define TXT_E2STS_SECRET_STS (1ull << 1) + +/* + * TXT Memory regions + * Chapter 5.3 + * Intel Trusted Execution Technology Lab Handout + */ +#define TXT_PRIVATE_SPACE 0xfed20000UL +#define TXT_PUBLIC_SPACE 0xfed30000UL +#define TXT_TPM_DECODE_AREA 0xfed40000UL +#define TXT_RESERVED_SPACE 0xfed50000UL + +#define TXT_RESERVED_SPACE_SIZE 0x3ffff + +/* ESI flags for GETSEC[ENTERACCS] see Reference Number: 323372-017 */ +#define ACMINPUT_RESET_TPM_AUXILIARY_INDICIES 2 +#define ACMINPUT_NOP 3 +#define ACMINPUT_SCHECK 4 +#define ACMINPUT_CLEAR_SECRETS 5 +#define ACMINPUT_LOCK_CONFIG 6 + +/* + * GetSec EAX value. + * SAFER MODE EXTENSIONS REFERENCE. + * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2 + * Order Number: 325383-060US + */ +#define IA32_GETSEC_CAPABILITIES 0 +#define IA32_GETSEC_ENTERACCS 2 +#define IA32_GETSEC_SENTER 4 +#define IA32_GETSEC_SEXIT 5 +#define IA32_GETSEC_PARAMETERS 6 +#define IA32_GETSEC_SMCTRL 7 +#define IA32_GETSEC_WAKEUP 8 + +#define GETSEC_PARAMS_TXT_EXT (1ul << 5) +#define GETSEC_PARAMS_TXT_EXT_CRTM_SUPPORT (1ul << 1) +#define GETSEC_PARAMS_TXT_EXT_MACHINE_CHECK (1ul << 6) + +/* ACM defines */ +#define INTEL_ACM_VENDOR 0x00008086 + +#define ACM_FORMAT_FLAGS_PW 0x00000000 +#define ACM_FORMAT_FLAGS_NPW (1 << 14) +#define ACM_FORMAT_FLAGS_DEBUG (1 << 15) + +/* Old ACMs are power of two aligned, newer ACMs are not */ +#define ACM_FORMAT_SIZE_64KB (64 * KiB / 4) +#define ACM_FORMAT_SIZE_128KB (128 * KiB / 4) +#define ACM_FORMAT_SIZE_256KB (256 * KiB / 4) + +/* MSRs */ +#define IA32_MCG_STATUS 0x17a + +typedef enum { + CHIPSET_ACM = 2, +} acm_module_type; + +typedef enum { + BIOS = 0, + SINIT = 1, +} acm_module_sub_type; + +/* + * ACM Header v0.0 without dynamic part + * Chapter A.1 + * Intel TXT Software Development Guide (Document: 315168-015) + */ +struct __packed acm_header_v0 { + uint16_t module_type; + uint16_t module_sub_type; + uint32_t header_len; + uint16_t header_version[2]; + uint16_t chipset_id; + uint16_t flags; + uint32_t module_vendor; + uint32_t date; + uint32_t size; + uint16_t txt_svn; + uint16_t se_svn; + uint32_t code_control; + uint32_t error_entry_point; + uint32_t gdt_limit; + uint32_t gdt_ptr; + uint32_t seg_sel; + uint32_t entry_point; + uint8_t reserved2[64]; + uint32_t key_size; + uint32_t scratch_size; + uint8_t rsa2048_pubkey[256]; + uint32_t pub_exp; + uint8_t rsa2048_sig[256]; + uint32_t scratch[143]; + uint8_t user_area[]; +}; + +struct __packed acm_info_table { + uint8_t uuid[16]; + uint8_t chipset_acm_type; + uint8_t version; + uint16_t length; + uint32_t chipset_id_list; + uint32_t os_sinit_data_ver; + uint32_t min_mle_hdr_ver; + uint32_t capabilities; + uint8_t acm_ver; + uint8_t reserved[3]; +}; + +/* + * Extended Data Elements + * Chapter C.1 + * Intel TXT Software Development Guide (Document: 315168-015) + */ +struct __packed txt_extended_data_element_header { + uint32_t type; + uint32_t size; + uint8_t data[0]; +}; + +#define HEAP_EXTDATA_TYPE_END 0 +#define HEAP_EXTDATA_TYPE_BIOS_SPEC_VER 1 +#define HEAP_EXTDATA_TYPE_ACM 2 +#define HEAP_EXTDATA_TYPE_CUSTOM 4 + +struct __packed txt_heap_acm_element { + struct txt_extended_data_element_header header; + uint32_t num_acms; // must greater 0, smaller than 3 + uint64_t acm_addrs[2]; +}; + +/* + * BIOS Data Format + * Chapter C.2 + * Intel TXT Software Development Guide (Document: 315168-015) + */ +struct __packed txt_biosdataregion { + uint32_t version; + uint32_t bios_sinit_size; + uint64_t lcp_pd_base; + uint64_t lcp_pd_size; + uint32_t no_logical_procs; + uint32_t sinit_flags; + union { + uint32_t mle_flags; + struct { + uint32_t support_acpi_ppi : 1; + uint32_t platform_type : 2; + }; + }; + u8 extended_data_elements[0]; +}; + + +void txt_dump_regions(void); +void txt_dump_chipset_info(void); +void txt_dump_acm_info(const struct acm_header_v0 *acm_header); + +#endif /* SECURITY_INTEL_TXT_REGISTER_H_ */ diff --git a/src/security/memory/memory.c b/src/security/memory/memory.c index c815236c9c..a1bc66372e 100644 --- a/src/security/memory/memory.c +++ b/src/security/memory/memory.c @@ -14,7 +14,8 @@ * GNU General Public License for more details. */ -#include +#include +#include #include "memory.h" /** @@ -27,6 +28,9 @@ bool security_clear_dram_request(void) if (CONFIG(SECURITY_CLEAR_DRAM_ON_REGULAR_BOOT)) return true; + if (CONFIG(INTEL_TXT) && intel_txt_memory_has_secrets()) + return true; + /* TODO: Add TEE environments here */ return false; From aae448601c0679171d711a70a03bcfe52b4accf3 Mon Sep 17 00:00:00 2001 From: Jonathan Zhang Date: Fri, 19 Jun 2020 12:41:13 -0700 Subject: [PATCH 21/67] soc/intel/fsp_broadwell_de: examine ACM status at romstage entry When INTEL_TXT is set, at romstage entry check if startup ACM worked correctly by probing TXT_ERROR register. Signed-off-by: Philipp Deppenwiese Signed-off-by: Jonathan Zhang Change-Id: I6f423df8b05dc44220a9bad3674f687bac94e335 Reviewed-on: https://review.coreboot.org/c/coreboot/+/42713 Reviewed-by: Angel Pons Tested-by: build bot (Jenkins) --- src/soc/intel/fsp_broadwell_de/romstage/romstage.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/soc/intel/fsp_broadwell_de/romstage/romstage.c b/src/soc/intel/fsp_broadwell_de/romstage/romstage.c index 8438b1035c..9699927574 100644 --- a/src/soc/intel/fsp_broadwell_de/romstage/romstage.c +++ b/src/soc/intel/fsp_broadwell_de/romstage/romstage.c @@ -38,6 +38,9 @@ #include #include +#include +#include + static void init_rtc(void) { u16 gen_pmcon3 = pci_read_config16(PCI_DEV(0, LPC_DEV, LPC_FUNC), GEN_PMCON_3); @@ -156,6 +159,12 @@ void *asmlinkage main(FSP_INFO_HEADER *fsp_info_header) early_iio_hide(); timestamp_add_now(TS_BEFORE_INITRAM); post_code(0x48); + + if (CONFIG(INTEL_TXT)) { + printk(BIOS_DEBUG, "Check TXT_ERROR register\n"); + intel_txt_log_acm_error(read32((void *)TXT_ERROR)); + } + /* * Call early init to initialize memory and chipset. This function returns * to the romstage_main_continue function with a pointer to the HOB From 6a7531431d1f9a8225529fc7b71ab57e0da984c3 Mon Sep 17 00:00:00 2001 From: Jonathan Zhang Date: Mon, 17 Aug 2020 15:22:54 -0700 Subject: [PATCH 22/67] mb/facebook/watson: increase size of RO_VPD and RW_VPD The current size of RO_VPD (and RW_VPD) is too small. We have case that adding VPD parameters silently corrupts the coreboot region next to RO_VPD. Increase the size of both RO_VPD and RW_VPD to 0x4000 bytes. TESTED=build coreboot image for watson, add large size VPD parameter to the image, boot watson server into target OS. Signed-off-by: Jonathan Zhang Change-Id: I428b7de6462b47492d9526042018395d2f99cb2a Reviewed-on: https://review.coreboot.org/c/coreboot/+/44531 Tested-by: build bot (Jenkins) Reviewed-by: Angel Pons Reviewed-by: Paul Menzel --- src/mainboard/facebook/watson/board.fmd | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mainboard/facebook/watson/board.fmd b/src/mainboard/facebook/watson/board.fmd index e2b8f58d06..6c58d12ebd 100644 --- a/src/mainboard/facebook/watson/board.fmd +++ b/src/mainboard/facebook/watson/board.fmd @@ -9,8 +9,8 @@ FLASH@0xff000000 0x1000000 { FMAP@0x0 0x1000 RW_MISC@0x1000 0xe000 { RW_ELOG@0x0 0x4000 - RW_VPD@0x4000 0x2000 - RW_MISC_UNUSED@0x6000 0x5000 + RW_VPD@0x4000 0x4000 + RW_MISC_UNUSED@0x8000 0x4000 RW_NVRAM@0xc000 0x2000 } UNIFIED_MRC_CACHE@0x10000 0x20000 { @@ -19,7 +19,7 @@ FLASH@0xff000000 0x1000000 { } # This only exists to satisfy tools that specifically # look for RO_VPD. - RO_VPD@0x30000 0x1000 - COREBOOT(CBFS)@0x31000 0x9cf000 + RO_VPD@0x30000 0x4000 + COREBOOT(CBFS)@0x34000 } } From a6956559157dc162afb94488dcd95e4e9dcfd14c Mon Sep 17 00:00:00 2001 From: Mario Scheithauer Date: Wed, 7 Oct 2020 14:48:01 +0200 Subject: [PATCH 23/67] mb/siemens/mc_bdx1: Fix IASL warning reported as error Latest IASL version (20200717) leads to a build error on 4.11_branch. dsdt.asl 1121: Device (UNC0) Warning 3073 - Multiple types (Device object requires either a _HID or _ADR, but not both) This warning reported as error was ignored in older IASL versions. The address object (_ADR) is not needed because a valid hardware ID (_HID) for the device is available. Change-Id: Iae5c91739ed9caea2dbb5996e2f093ed6fc47e93 Signed-off-by: Mario Scheithauer Reviewed-on: https://review.coreboot.org/c/coreboot/+/46129 Tested-by: build bot (Jenkins) Reviewed-by: HAOUAS Elyes Reviewed-by: Stefan Reinauer Reviewed-by: Angel Pons Reviewed-by: Christian Walter --- src/mainboard/siemens/mc_bdx1/dsdt.asl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mainboard/siemens/mc_bdx1/dsdt.asl b/src/mainboard/siemens/mc_bdx1/dsdt.asl index 1248703266..76845f549f 100644 --- a/src/mainboard/siemens/mc_bdx1/dsdt.asl +++ b/src/mainboard/siemens/mc_bdx1/dsdt.asl @@ -261,7 +261,6 @@ DefinitionBlock( Return (0xff) } - Name (_ADR, 0x00) Method (_STA, 0, NotSerialized) { Return (0xf) From 76b81ff4c7bc880cb010cd849720e25c1a3124f7 Mon Sep 17 00:00:00 2001 From: Marc Jones Date: Thu, 29 Oct 2020 14:43:49 -0600 Subject: [PATCH 24/67] ocp/monolake: Simplify mainboard dsdt.asl Include the soc uncore.asl for the uncore irq routing. Generates the same asl. Change-Id: I2062520a06626f86fb0d78e8b23533f987b37ca0 Signed-off-by: Marc Jones Reviewed-on: https://review.coreboot.org/c/coreboot/+/46985 Tested-by: build bot (Jenkins) Reviewed-by: Jay Talbott Reviewed-by: Stefan Reinauer --- src/mainboard/ocp/monolake/dsdt.asl | 251 +--------------------------- 1 file changed, 1 insertion(+), 250 deletions(-) diff --git a/src/mainboard/ocp/monolake/dsdt.asl b/src/mainboard/ocp/monolake/dsdt.asl index 1248703266..0d9e90dab3 100644 --- a/src/mainboard/ocp/monolake/dsdt.asl +++ b/src/mainboard/ocp/monolake/dsdt.asl @@ -38,256 +38,7 @@ DefinitionBlock( #include } - Name (PRUN, Package() { - Package() { 0x0008FFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 }, - Package() { 0x0008FFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 }, - Package() { 0x0008FFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 }, - Package() { 0x0008FFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 }, - - Package() { 0x0009FFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 }, - Package() { 0x0009FFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 }, - Package() { 0x0009FFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 }, - Package() { 0x0009FFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 }, - - Package() { 0x000AFFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 }, - Package() { 0x000AFFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 }, - Package() { 0x000AFFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 }, - Package() { 0x000AFFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 }, - - Package() { 0x000BFFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 }, - Package() { 0x000BFFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 }, - Package() { 0x000BFFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 }, - Package() { 0x000BFFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 }, - - Package() { 0x000CFFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 }, - Package() { 0x000CFFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 }, - Package() { 0x000CFFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 }, - Package() { 0x000CFFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 }, - - Package() { 0x000DFFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 }, - Package() { 0x000DFFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 }, - Package() { 0x000DFFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 }, - Package() { 0x000DFFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 }, - - Package() { 0x000EFFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 }, - Package() { 0x000EFFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 }, - Package() { 0x000EFFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 }, - Package() { 0x000EFFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 }, - - Package() { 0x000FFFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 }, - Package() { 0x000FFFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 }, - Package() { 0x000FFFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 }, - Package() { 0x000FFFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 }, - - Package() { 0x0010FFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 }, - Package() { 0x0010FFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 }, - Package() { 0x0010FFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 }, - Package() { 0x0010FFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 }, - - Package() { 0x0011FFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 }, - Package() { 0x0011FFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 }, - Package() { 0x0011FFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 }, - Package() { 0x0011FFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 }, - - Package() { 0x0012FFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 }, - Package() { 0x0012FFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 }, - Package() { 0x0012FFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 }, - Package() { 0x0012FFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 }, - - Package() { 0x0013FFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 }, - Package() { 0x0013FFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 }, - Package() { 0x0013FFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 }, - Package() { 0x0013FFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 }, - - Package() { 0x0014FFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 }, - Package() { 0x0014FFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 }, - Package() { 0x0014FFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 }, - Package() { 0x0014FFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 }, - - Package() { 0x0016FFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 }, - Package() { 0x0016FFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 }, - Package() { 0x0016FFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 }, - Package() { 0x0016FFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 }, - - Package() { 0x0017FFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 }, - Package() { 0x0017FFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 }, - Package() { 0x0017FFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 }, - Package() { 0x0017FFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 }, - - Package() { 0x0018FFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 }, - Package() { 0x0018FFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 }, - Package() { 0x0018FFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 }, - Package() { 0x0018FFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 }, - - Package() { 0x0019FFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 }, - Package() { 0x0019FFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 }, - Package() { 0x0019FFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 }, - Package() { 0x0019FFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 }, - - Package() { 0x001CFFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 }, - Package() { 0x001CFFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 }, - Package() { 0x001CFFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 }, - Package() { 0x001CFFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 }, - - Package() { 0x001DFFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 }, - Package() { 0x001DFFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 }, - Package() { 0x001DFFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 }, - Package() { 0x001DFFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 }, - - Package() { 0x001EFFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 }, - Package() { 0x001EFFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 }, - Package() { 0x001EFFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 }, - Package() { 0x001EFFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 }, - - Package() { 0x001FFFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 }, - Package() { 0x001FFFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 }, - Package() { 0x001FFFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 }, - Package() { 0x001FFFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 }, - }) - - Name (ARUN, Package() { - Package() { 0x0008FFFF, 0, 0, 16 }, - Package() { 0x0008FFFF, 1, 0, 17 }, - Package() { 0x0008FFFF, 2, 0, 18 }, - Package() { 0x0008FFFF, 3, 0, 19 }, - - Package() { 0x0009FFFF, 0, 0, 16 }, - Package() { 0x0009FFFF, 1, 0, 17 }, - Package() { 0x0009FFFF, 2, 0, 18 }, - Package() { 0x0009FFFF, 3, 0, 19 }, - - Package() { 0x000AFFFF, 0, 0, 16 }, - Package() { 0x000AFFFF, 1, 0, 17 }, - Package() { 0x000AFFFF, 2, 0, 18 }, - Package() { 0x000AFFFF, 3, 0, 19 }, - - Package() { 0x000BFFFF, 0, 0, 16 }, - Package() { 0x000BFFFF, 1, 0, 17 }, - Package() { 0x000BFFFF, 2, 0, 18 }, - Package() { 0x000BFFFF, 3, 0, 19 }, - - Package() { 0x000CFFFF, 0, 0, 16 }, - Package() { 0x000CFFFF, 1, 0, 17 }, - Package() { 0x000CFFFF, 2, 0, 18 }, - Package() { 0x000CFFFF, 3, 0, 19 }, - - Package() { 0x000DFFFF, 0, 0, 16 }, - Package() { 0x000DFFFF, 1, 0, 17 }, - Package() { 0x000DFFFF, 2, 0, 18 }, - Package() { 0x000DFFFF, 3, 0, 19 }, - - Package() { 0x000EFFFF, 0, 0, 16 }, - Package() { 0x000EFFFF, 1, 0, 17 }, - Package() { 0x000EFFFF, 2, 0, 18 }, - Package() { 0x000EFFFF, 3, 0, 19 }, - - Package() { 0x000FFFFF, 0, 0, 16 }, - Package() { 0x000FFFFF, 1, 0, 17 }, - Package() { 0x000FFFFF, 2, 0, 18 }, - Package() { 0x000FFFFF, 3, 0, 19 }, - - Package() { 0x0010FFFF, 0, 0, 16 }, - Package() { 0x0010FFFF, 1, 0, 17 }, - Package() { 0x0010FFFF, 2, 0, 18 }, - Package() { 0x0010FFFF, 3, 0, 19 }, - - Package() { 0x0011FFFF, 0, 0, 16 }, - Package() { 0x0011FFFF, 1, 0, 17 }, - Package() { 0x0011FFFF, 2, 0, 18 }, - Package() { 0x0011FFFF, 3, 0, 19 }, - - Package() { 0x0012FFFF, 0, 0, 16 }, - Package() { 0x0012FFFF, 1, 0, 17 }, - Package() { 0x0012FFFF, 2, 0, 18 }, - Package() { 0x0012FFFF, 3, 0, 19 }, - - Package() { 0x0013FFFF, 0, 0, 16 }, - Package() { 0x0013FFFF, 1, 0, 17 }, - Package() { 0x0013FFFF, 2, 0, 18 }, - Package() { 0x0013FFFF, 3, 0, 19 }, - - Package() { 0x0014FFFF, 0, 0, 16 }, - Package() { 0x0014FFFF, 1, 0, 17 }, - Package() { 0x0014FFFF, 2, 0, 18 }, - Package() { 0x0014FFFF, 3, 0, 19 }, - - Package() { 0x0016FFFF, 0, 0, 16 }, - Package() { 0x0016FFFF, 1, 0, 17 }, - Package() { 0x0016FFFF, 2, 0, 18 }, - Package() { 0x0016FFFF, 3, 0, 19 }, - - Package() { 0x0017FFFF, 0, 0, 16 }, - Package() { 0x0017FFFF, 1, 0, 17 }, - Package() { 0x0017FFFF, 2, 0, 18 }, - Package() { 0x0017FFFF, 3, 0, 19 }, - - Package() { 0x0018FFFF, 0, 0, 16 }, - Package() { 0x0018FFFF, 1, 0, 17 }, - Package() { 0x0018FFFF, 2, 0, 18 }, - Package() { 0x0018FFFF, 3, 0, 19 }, - - Package() { 0x0019FFFF, 0, 0, 16 }, - Package() { 0x0019FFFF, 1, 0, 17 }, - Package() { 0x0019FFFF, 2, 0, 18 }, - Package() { 0x0019FFFF, 3, 0, 19 }, - - Package() { 0x001CFFFF, 0, 0, 16 }, - Package() { 0x001CFFFF, 1, 0, 17 }, - Package() { 0x001CFFFF, 2, 0, 18 }, - Package() { 0x001CFFFF, 3, 0, 19 }, - - Package() { 0x001DFFFF, 0, 0, 16 }, - Package() { 0x001DFFFF, 1, 0, 17 }, - Package() { 0x001DFFFF, 2, 0, 18 }, - Package() { 0x001DFFFF, 3, 0, 19 }, - - Package() { 0x001EFFFF, 0, 0, 16 }, - Package() { 0x001EFFFF, 1, 0, 17 }, - Package() { 0x001EFFFF, 2, 0, 18 }, - Package() { 0x001EFFFF, 3, 0, 19 }, - - Package() { 0x001FFFFF, 0, 0, 16 }, - Package() { 0x001FFFFF, 1, 0, 17 }, - Package() { 0x001FFFFF, 2, 0, 18 }, - Package() { 0x001FFFFF, 3, 0, 19 }, - }) - - Device (UNC0) - { - Name (_HID, EisaId ("PNP0A03")) - Name (_UID, 0x3F) - Method (_BBN, 0, NotSerialized) - { - Return (0xff) - } - - Name (_ADR, 0x00) - Method (_STA, 0, NotSerialized) - { - Return (0xf) - } - - Name (_CRS, ResourceTemplate () - { - WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode, - 0x0000, // Granularity - 0x00FF, // Range Minimum - 0x00FF, // Range Maximum - 0x0000, // Translation Offset - 0x0001, // Length - ,, ) - }) - - Method (_PRT, 0, NotSerialized) - { - If (LEqual (PICM, Zero)) - { - Return (PRUN) - } - - Return (ARUN) - } - } + #include } #include "acpi/mainboard.asl" From 1c7b526de11924b36bf86f305f419830349774b9 Mon Sep 17 00:00:00 2001 From: Arthur Heymans Date: Thu, 15 Oct 2020 13:52:20 +0200 Subject: [PATCH 25/67] sec/intel/txt/Kconfig: Remove the menu for including ACMs This is consistent with how other binaries (e.g. FSP) are added via Kconfig. This also makes it more visible that things need to be configured. Change-Id: I399de6270cc4c0ab3b8c8a9543aec0d68d3cfc03 Signed-off-by: Arthur Heymans Reviewed-on: https://review.coreboot.org/c/coreboot/+/45003 Tested-by: build bot (Jenkins) --- src/security/intel/txt/Kconfig | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/security/intel/txt/Kconfig b/src/security/intel/txt/Kconfig index d828a9de13..049705fc6c 100644 --- a/src/security/intel/txt/Kconfig +++ b/src/security/intel/txt/Kconfig @@ -26,8 +26,6 @@ config INTEL_TXT if INTEL_TXT -menu "Intel" - config INTEL_TXT_BIOSACM_FILE string "BIOS ACM file" default "3rdparty/blobs/soc/intel/fsp_broadwell_de/biosacm.bin" if SOC_INTEL_FSP_BROADWELL_DE @@ -71,6 +69,4 @@ config INTEL_TXT_CBFS_SINIT_ACM string default "txt_sinit_acm.bin" -endmenu # Intel - endif From 1474ddb722d131d1534c958dbb7136e73a34268f Mon Sep 17 00:00:00 2001 From: Philipp Deppenwiese Date: Fri, 18 Dec 2020 19:40:55 +0100 Subject: [PATCH 26/67] security/tpm: Add crypto agility support * Added tlcl_extend size checks * Added TPM2 tlcl_extend crypto agility TESTED=On Facebook Watson_V2 mainboard, the TCPA log now shows correct hash content and algorithm: PCR-0 62571891215b4efc1ceab744ce59dd0b66ea6f73 SHA1 [VBOOT: boot mode] instead of: PCR-0 62571891215b4efc1ceab744ce59dd0b66ea6f73 SHA256 [VBOOT: boot mode] Change-Id: I9cc8d994081896e8c0d511c31e9741297227afef Signed-off-by: Philipp Deppenwiese Reviewed-on: https://review.coreboot.org/c/coreboot/+/48742 Tested-by: build bot (Jenkins) Reviewed-by: Angel Pons --- src/security/tpm/tspi/tspi.c | 19 ++++++++++- src/security/tpm/tss.h | 3 +- src/security/tpm/tss/tcg-1.2/tss.c | 8 +++-- src/security/tpm/tss/tcg-2.0/tss.c | 38 +++++++++++++++++---- src/security/vboot/tpm_common.c | 2 +- src/vendorcode/eltan/security/mboot/mboot.c | 3 +- 6 files changed, 61 insertions(+), 12 deletions(-) diff --git a/src/security/tpm/tspi/tspi.c b/src/security/tpm/tspi/tspi.c index 966b8b7c77..795016e725 100644 --- a/src/security/tpm/tspi/tspi.c +++ b/src/security/tpm/tspi/tspi.c @@ -210,11 +210,28 @@ uint32_t tpm_extend_pcr(int pcr, enum vb2_hash_algorithm digest_algo, uint8_t *digest, size_t digest_len, const char *name) { uint32_t result; + uint16_t algorithm = 0; if (!digest) return TPM_E_IOERROR; - result = tlcl_extend(pcr, digest, NULL); +#if CONFIG(TPM2) + switch (digest_algo) { + case VB2_HASH_SHA1: + algorithm = TPM_ALG_SHA1; + break; + case VB2_HASH_SHA256: + algorithm = TPM_ALG_SHA256; + break; + case VB2_HASH_SHA512: + algorithm = TPM_ALG_SHA512; + break; + default: + return TPM_E_HASH_ERROR; + } +#endif + + result = tlcl_extend(pcr, algorithm, digest, digest_len, NULL); if (result != TPM_SUCCESS) return result; diff --git a/src/security/tpm/tss.h b/src/security/tpm/tss.h index 336935d911..c1ba234c2c 100644 --- a/src/security/tpm/tss.h +++ b/src/security/tpm/tss.h @@ -184,7 +184,8 @@ uint32_t tlcl_lock_nv_write(uint32_t index); /** * Perform a TPM_Extend. */ -uint32_t tlcl_extend(int pcr_num, const uint8_t *in_digest, +uint32_t tlcl_extend(int pcr_num, uint16_t algorithm, + const uint8_t *in_digest, size_t in_digest_len, uint8_t *out_digest); /** diff --git a/src/security/tpm/tss/tcg-1.2/tss.c b/src/security/tpm/tss/tcg-1.2/tss.c index b11d6a3d16..4c980d0d79 100644 --- a/src/security/tpm/tss/tcg-1.2/tss.c +++ b/src/security/tpm/tss/tcg-1.2/tss.c @@ -341,7 +341,8 @@ uint32_t tlcl_set_global_lock(void) return tlcl_write(TPM_NV_INDEX0, (uint8_t *) &x, 0); } -uint32_t tlcl_extend(int pcr_num, const uint8_t *in_digest, +uint32_t tlcl_extend(int pcr_num, uint16_t algorithm, + const uint8_t *in_digest, size_t in_digest_len, uint8_t *out_digest) { struct s_tpm_extend_cmd cmd; @@ -350,8 +351,11 @@ uint32_t tlcl_extend(int pcr_num, const uint8_t *in_digest, memcpy(&cmd, &tpm_extend_cmd, sizeof(cmd)); to_tpm_uint32(cmd.buffer + tpm_extend_cmd.pcrNum, pcr_num); - memcpy(cmd.buffer + cmd.inDigest, in_digest, kPcrDigestLength); + if (in_digest_len != kPcrDigestLength) + return TPM_E_HASH_ERROR; + + memcpy(cmd.buffer + cmd.inDigest, in_digest, kPcrDigestLength); result = tlcl_send_receive(cmd.buffer, response, sizeof(response)); if (result != TPM_SUCCESS) return result; diff --git a/src/security/tpm/tss/tcg-2.0/tss.c b/src/security/tpm/tss/tcg-2.0/tss.c index 16e40fe569..ac43549d84 100644 --- a/src/security/tpm/tss/tcg-2.0/tss.c +++ b/src/security/tpm/tss/tcg-2.0/tss.c @@ -127,21 +127,47 @@ uint32_t tlcl_assert_physical_presence(void) } /* - * The caller will provide the digest in a 32 byte buffer, let's consider it a - * sha256 digest. + * The caller will provide the pcr index, digest algorithm and + * a byte buffer to extend into the TPM. */ -uint32_t tlcl_extend(int pcr_num, const uint8_t *in_digest, +uint32_t tlcl_extend(int pcr_num, uint16_t algorithm, + const uint8_t *in_digest, size_t in_digest_len, uint8_t *out_digest) { struct tpm2_pcr_extend_cmd pcr_ext_cmd; struct tpm2_response *response; + uint16_t algorithm_size; pcr_ext_cmd.pcrHandle = HR_PCR + pcr_num; pcr_ext_cmd.digests.count = 1; - pcr_ext_cmd.digests.digests[0].hashAlg = TPM_ALG_SHA256; - memcpy(pcr_ext_cmd.digests.digests[0].digest.sha256, in_digest, - sizeof(pcr_ext_cmd.digests.digests[0].digest.sha256)); + pcr_ext_cmd.digests.digests[0].hashAlg = algorithm; + algorithm_size = tlcl_get_hash_size_from_algo(algorithm); + if (algorithm_size == 0) + return TPM_E_HASH_ERROR; + + if (in_digest_len != algorithm_size) + return TPM_E_HASH_ERROR; + + switch (algorithm) { + case TPM_ALG_SHA1: + memcpy(pcr_ext_cmd.digests.digests[0].digest.sha1, in_digest, in_digest_len); + break; + case TPM_ALG_SHA256: + memcpy(pcr_ext_cmd.digests.digests[0].digest.sha256, in_digest, in_digest_len); + break; + case TPM_ALG_SHA384: + memcpy(pcr_ext_cmd.digests.digests[0].digest.sha384, in_digest, in_digest_len); + break; + case TPM_ALG_SHA512: + memcpy(pcr_ext_cmd.digests.digests[0].digest.sha512, in_digest, in_digest_len); + break; + case TPM_ALG_SM3_256: + memcpy(pcr_ext_cmd.digests.digests[0].digest.sm3_256, in_digest, in_digest_len); + break; + default: + return TPM_E_HASH_ERROR; + } response = tpm_process_command(TPM2_PCR_Extend, &pcr_ext_cmd); printk(BIOS_INFO, "%s: response is %x\n", diff --git a/src/security/vboot/tpm_common.c b/src/security/vboot/tpm_common.c index 0a211c57d4..1db7189d7a 100644 --- a/src/security/vboot/tpm_common.c +++ b/src/security/vboot/tpm_common.c @@ -46,7 +46,7 @@ vb2_error_t vboot_extend_pcr(struct vb2_context *ctx, int pcr, switch (which_digest) { /* SHA1 of (devmode|recmode|keyblock) bits */ case BOOT_MODE_PCR: - return tpm_extend_pcr(pcr, VB2_HASH_SHA256, buffer, size, + return tpm_extend_pcr(pcr, VB2_HASH_SHA1, buffer, size, TPM_PCR_BOOT_MODE); /* SHA256 of HWID */ case HWID_DIGEST_PCR: diff --git a/src/vendorcode/eltan/security/mboot/mboot.c b/src/vendorcode/eltan/security/mboot/mboot.c index c5523a5fd8..499d35299c 100644 --- a/src/vendorcode/eltan/security/mboot/mboot.c +++ b/src/vendorcode/eltan/security/mboot/mboot.c @@ -150,7 +150,8 @@ int mboot_hash_extend_log(uint64_t flags, uint8_t *hashData, uint32_t hashDataLe printk(BIOS_DEBUG, "%s: SHA256 Hash Digest:\n", __func__); mboot_print_buffer(digest->digest.sha256, VB2_SHA256_DIGEST_SIZE); - return (tlcl_extend(newEventHdr->pcrIndex, (uint8_t *)&(newEventHdr->digest), NULL)); + return (tlcl_extend(newEventHdr->pcrIndex, newEventHdr->digest.digests[0].hashAlg, + (uint8_t *)&(newEventHdr->digest), hashDataLen, NULL)); } /* From 2085d6f46ad54d7148de38ddd0d183911c2732cc Mon Sep 17 00:00:00 2001 From: "Deomid \"rojer\" Ryabkov" Date: Wed, 3 Feb 2021 17:46:29 +0000 Subject: [PATCH 27/67] Apply locked MSR check to all BDW-DE platforms It was initially applied to Wedge100 and MonoLake in CB:30290 and the issue has now been observed on Watson as well. Original change: [CB:30290][commit 817994c1be] Signed-off-by: Deomid "rojer" Ryabkov Change-Id: Ica9557ff159321abed55f9402aee626f18fe526b Reviewed-on: https://review.coreboot.org/c/coreboot/+/50307 Reviewed-by: Angel Pons Tested-by: build bot (Jenkins) --- src/mainboard/ocp/monolake/romstage.c | 18 +-------------- src/mainboard/ocp/wedge100s/romstage.c | 22 ------------------- .../fsp_broadwell_de/romstage/romstage.c | 21 ++++++++++++++++++ 3 files changed, 22 insertions(+), 39 deletions(-) diff --git a/src/mainboard/ocp/monolake/romstage.c b/src/mainboard/ocp/monolake/romstage.c index ef41b7720e..ebc43de823 100644 --- a/src/mainboard/ocp/monolake/romstage.c +++ b/src/mainboard/ocp/monolake/romstage.c @@ -19,9 +19,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -193,20 +190,7 @@ static const struct gpio_config gpio_tables[] = { */ void early_mainboard_romstage_entry(void) { - /* - * Sometimes the system boots in an invalid state, where random values - * have been written to MSRs and then the MSRs are locked. - * Seems to always happen on warm reset. - * - * Power cycling or a board_reset() isn't sufficient in this case, so - * issue a full_reset() to "fix" this issue. - */ - msr_t msr = rdmsr(IA32_FEATURE_CONTROL); - if (msr.lo & 1) { - console_init(); - printk(BIOS_EMERG, "Detected broken platform state. Issuing full reset\n"); - full_reset(); - } + } /** diff --git a/src/mainboard/ocp/wedge100s/romstage.c b/src/mainboard/ocp/wedge100s/romstage.c index 108d7a1c4d..b1f8f26796 100644 --- a/src/mainboard/ocp/wedge100s/romstage.c +++ b/src/mainboard/ocp/wedge100s/romstage.c @@ -17,9 +17,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -44,25 +41,6 @@ void early_mainboard_romstage_entry(void) if (CONFIG(CONSOLE_SERIAL)) ite_enable_serial(SERIAL_DEV, CONFIG_TTYS0_BASE); - - - /* - * Sometimes the system boots in an invalid state, where random values - * have been written to MSRs and then the MSRs are locked. - * Seems to always happen on warm reset. - * - * Power cycling or a board_reset() isn't sufficient in this case, so - * issue a full_reset() to "fix" this issue. - * - * It seems to be a deficiency in the reset logic, as other - * FSP broadwell DE boards are not affected. - */ - msr_t msr = rdmsr(IA32_FEATURE_CONTROL); - if (msr.lo & 1) { - console_init(); - printk(BIOS_EMERG, "Detected broken platform state. Issuing full reset\n"); - full_reset(); - } } /** diff --git a/src/soc/intel/fsp_broadwell_de/romstage/romstage.c b/src/soc/intel/fsp_broadwell_de/romstage/romstage.c index 9699927574..dbf4bc3482 100644 --- a/src/soc/intel/fsp_broadwell_de/romstage/romstage.c +++ b/src/soc/intel/fsp_broadwell_de/romstage/romstage.c @@ -21,8 +21,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -125,7 +127,24 @@ static void early_iio_hide(void) iio_hide(dev); } } +} +static void check_msr_lock(void) +{ + /* + * Sometimes the system boots in an invalid state, where random values + * have been written to MSRs and then the MSRs are locked. + * Seems to always happen on warm reset. + * + * Power cycling or a board_reset() isn't sufficient in this case, so + * issue a full_reset() to "fix" this issue. + */ + msr_t msr = rdmsr(IA32_FEATURE_CONTROL); + if (msr.lo & 1) { + console_init(); + printk(BIOS_EMERG, "Detected broken platform state. Issuing full reset\n"); + full_reset(); + } } /* Entry from cache-as-ram.inc. */ @@ -146,6 +165,8 @@ void *asmlinkage main(FSP_INFO_HEADER *fsp_info_header) enable_integrated_uart(CONFIG_UART_FOR_CONSOLE); } + check_msr_lock(); + /* Call into mainboard. */ post_code(0x41); early_mainboard_romstage_entry(); From bff4cb055875e59bf436de5ca4f5c5666626abaf Mon Sep 17 00:00:00 2001 From: Eugene Myers Date: Tue, 21 Jan 2020 17:01:47 -0500 Subject: [PATCH 28/67] security/intel/stm: Add STM support This update is a combination of all four of the patches so that the commit can be done without breaking parts of coreboot. This possible breakage is because of the cross-dependencies between the original separate patches would cause failure because of data structure changes. security/intel/stm This directory contains the functions that check and move the STM to the MSEG, create its page tables, and create the BIOS resource list. The STM page tables is a six page region located in the MSEG and are pointed to by the CR3 Offset field in the MSEG header. The initial page tables will identity map all memory between 0-4G. The STM starts in IA32e mode, which requires page tables to exist at startup. The BIOS resource list defines the resources that the SMI Handler is allowed to access. This includes the SMM memory area where the SMI handler resides and other resources such as I/O devices. The STM uses the BIOS resource list to restrict the SMI handler's accesses. The BIOS resource list is currently located in the same area as the SMI handler. This location is shown in the comment section before smm_load_module in smm_module_loader.c Note: The files within security/intel/stm come directly from their Tianocore counterparts. Unnecessary code has been removed and the remaining code has been converted to meet coreboot coding requirements. For more information see: SMI Transfer Monitor (STM) User Guide, Intel Corp., August 2015, Rev 1.0, can be found at firmware.intel.com include/cpu/x86: Addtions to include/cpu/x86 for STM support. cpu/x86: STM Set up - The STM needs to be loaded into the MSEG during BIOS initialization and the SMM Monitor Control MSR be set to indicate that an STM is in the system. cpu/x86/smm: SMI module loader modifications needed to set up the SMM descriptors used by the STM during its initialization Original-Change-Id: If4adcd92c341162630ce1ec357ffcf8a135785ec Original-Signed-off-by: Eugene D. Myers Original-Reviewed-on: https://review.coreboot.org/c/coreboot/+/33234 Original-Tested-by: build bot (Jenkins) Original-Reviewed-by: Patrick Georgi Original-Reviewed-by: ron minnich (cherry picked from commit ae438be57856e994774ec0e2521d49f1ad09bd6f) Signed-off-by: Marc Jones Change-Id: Ic0131fcada9f43c9817c8a0a942d0419c7023130 Reviewed-on: https://review.coreboot.org/c/coreboot/+/50308 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer --- configs/config.stm | 4 + src/cpu/x86/mp_init.c | 34 + src/cpu/x86/smm/smm_module_loader.c | 19 +- src/cpu/x86/smm/smm_stub.S | 13 + src/include/cpu/x86/msr.h | 10 + src/include/cpu/x86/smm.h | 3 + src/security/intel/Kconfig | 1 + src/security/intel/Makefile.inc | 1 + src/security/intel/stm/Kconfig | 49 ++ src/security/intel/stm/Makefile.inc | 10 + src/security/intel/stm/SmmStm.c | 691 ++++++++++++++++++ src/security/intel/stm/SmmStm.h | 120 +++ src/security/intel/stm/StmApi.h | 726 +++++++++++++++++++ src/security/intel/stm/StmPlatformResource.c | 188 +++++ src/security/intel/stm/StmPlatformResource.h | 32 + src/security/intel/stm/StmPlatformSmm.c | 204 ++++++ 16 files changed, 2104 insertions(+), 1 deletion(-) create mode 100644 configs/config.stm create mode 100644 src/security/intel/stm/Kconfig create mode 100644 src/security/intel/stm/Makefile.inc create mode 100644 src/security/intel/stm/SmmStm.c create mode 100644 src/security/intel/stm/SmmStm.h create mode 100644 src/security/intel/stm/StmApi.h create mode 100644 src/security/intel/stm/StmPlatformResource.c create mode 100644 src/security/intel/stm/StmPlatformResource.h create mode 100644 src/security/intel/stm/StmPlatformSmm.c diff --git a/configs/config.stm b/configs/config.stm new file mode 100644 index 0000000000..59792b2fa5 --- /dev/null +++ b/configs/config.stm @@ -0,0 +1,4 @@ +CONFIG_VENDOR_PURISM=y +CONFIG_BOARD_PURISM_LIBREM15_V4=y +CONFIG_STM=y +CONFIG_IED_REGION_SIZE=0 diff --git a/src/cpu/x86/mp_init.c b/src/cpu/x86/mp_init.c index 29ae3de87a..32450c8212 100644 --- a/src/cpu/x86/mp_init.c +++ b/src/cpu/x86/mp_init.c @@ -37,6 +37,8 @@ #include #include +#include + #define MAX_APIC_IDS 256 struct mp_callback { @@ -741,6 +743,23 @@ static void asmlinkage smm_do_relocation(void *arg) /* Setup code checks this callback for validity. */ mp_state.ops.relocation_handler(cpu, curr_smbase, perm_smbase); + + if (CONFIG(STM)) { + if (is_smm_enabled()) { + uintptr_t mseg; + + mseg = mp_state.perm_smbase + + (mp_state.perm_smsize - CONFIG_MSEG_SIZE); + + stm_setup(mseg, p->cpu, runtime->num_cpus, + perm_smbase, + mp_state.perm_smbase, + runtime->start32_offset); + } else { + printk(BIOS_DEBUG, + "STM not loaded because SMM is not enabled!\n"); + } + } } static void adjust_smm_apic_id_map(struct smm_loader_params *smm_params) @@ -1020,6 +1039,21 @@ static void fill_mp_state(struct mp_state *state, const struct mp_ops *ops) ops->get_smm_info(&state->perm_smbase, &state->perm_smsize, &state->smm_save_state_size); + /* + * Make sure there is enough room for the SMM descriptor + */ + if (CONFIG(STM)) + state->smm_save_state_size += + sizeof(TXT_PROCESSOR_SMM_DESCRIPTOR); + + /* Currently, the CPU SMM save state size is based on a simplistic + * algorithm. (align on 4K) + * note: In the future, this will need to handle newer x86 processors + * that require alignment of the save state on 32K boundaries. + */ + state->smm_save_state_size = + ALIGN_UP(state->smm_save_state_size, 0x1000); + /* * Default to smm_initiate_relocation() if trigger callback isn't * provided. diff --git a/src/cpu/x86/smm/smm_module_loader.c b/src/cpu/x86/smm/smm_module_loader.c index c6c6b38737..a421436893 100644 --- a/src/cpu/x86/smm/smm_module_loader.c +++ b/src/cpu/x86/smm/smm_module_loader.c @@ -17,6 +17,7 @@ #include #include #include +#include #define FXSAVE_SIZE 512 @@ -267,6 +268,7 @@ static int smm_module_setup_stub(void *smbase, struct smm_loader_params *params, stub_params->fxsave_area_size = FXSAVE_SIZE; stub_params->runtime.smbase = (uintptr_t)smbase; stub_params->runtime.save_state_size = params->per_cpu_save_state_size; + stub_params->runtime.num_cpus = params->num_concurrent_stacks; /* Initialize the APIC id to CPU number table to be 1:1 */ for (i = 0; i < params->num_concurrent_stacks; i++) @@ -313,6 +315,11 @@ int smm_setup_relocation_handler(struct smm_loader_params *params) * +-----------------+ <- smram + size * | stacks | * +-----------------+ <- smram + size - total_stack_size + * | fxsave area | + * +-----------------+ <- smram + size - total_stack_size - fxsave_size + * | BIOS resource | + * | list (STM) | + * +-----------------+ <- .. - CONFIG_BIOS_RESOURCE_LIST_SIZE * | ... | * +-----------------+ <- smram + handler_size + SMM_DEFAULT_SIZE * | handler | @@ -353,7 +360,12 @@ int smm_load_module(void *smram, size_t size, struct smm_loader_params *params) /* Stacks start at the top of the region. */ base = smram; - base += size; + + if (CONFIG(STM)) + base += size - CONFIG_MSEG_SIZE; // take out the mseg + else + base += size; + params->stack_top = base; /* SMM module starts at offset SMM_DEFAULT_SIZE with the load alignment @@ -382,6 +394,11 @@ int smm_load_module(void *smram, size_t size, struct smm_loader_params *params) /* Does the required amount of memory exceed the SMRAM region size? */ total_size = total_stack_size + handler_size; total_size += fxsave_size + SMM_DEFAULT_SIZE; + + // account for the bios resource list + if (CONFIG(STM)) + total_size += CONFIG_BIOS_RESOURCE_LIST_SIZE; + if (total_size > size) return -1; diff --git a/src/cpu/x86/smm/smm_stub.S b/src/cpu/x86/smm/smm_stub.S index f0e55f9a18..8207d233a0 100644 --- a/src/cpu/x86/smm/smm_stub.S +++ b/src/cpu/x86/smm/smm_stub.S @@ -44,6 +44,11 @@ smbase: .long 0 save_state_size: .long 0 +num_cpus: +.long 0 +/* allows the STM to bring up SMM in 32-bit mode */ +start32_offset: +.long smm_trampoline32 - _start /* apic_to_cpu_num is a table mapping the default APIC id to CPU num. If the * APIC id is found at the given index, the contiguous CPU number is index * into the table. */ @@ -90,6 +95,14 @@ smm_relocate_gdt: /* gdt selector 0x10, flat data segment */ .word 0xffff, 0x0000 .byte 0x00, 0x93, 0xcf, 0x00 + + /* gdt selector 0x18, flat code segment (64-bit) */ + .word 0xffff, 0x0000 + .byte 0x00, 0x9b, 0xcf, 0x00 + + /* gdt selector 0x20 tss segment */ + .word 0xffff, 0x0000 + .byte 0x00, 0x8b, 0x80, 0x00 smm_relocate_gdt_end: .align 4 diff --git a/src/include/cpu/x86/msr.h b/src/include/cpu/x86/msr.h index 2710e7f1fc..ad07742d2f 100644 --- a/src/include/cpu/x86/msr.h +++ b/src/include/cpu/x86/msr.h @@ -16,6 +16,7 @@ /* Page attribute type MSR */ #define TSC_MSR 0x10 #define IA32_PLATFORM_ID 0x17 +#define IA32_APIC_BASE_MSR_INDEX 0x1B #define IA32_FEATURE_CONTROL 0x3a #define FEATURE_CONTROL_LOCK_BIT (1 << 0) #define FEATURE_ENABLE_VMX (1 << 2) @@ -30,6 +31,10 @@ #define IA32_BIOS_SIGN_ID 0x8b #define IA32_MPERF 0xe7 #define IA32_APERF 0xe8 +/* STM */ +#define IA32_SMM_MONITOR_CTL_MSR 0x9B +#define SMBASE_RO_MSR 0x98 +#define IA32_SMM_MONITOR_VALID (1 << 0) #define IA32_MCG_CAP 0x179 #define MCG_CTL_P (1 << 3) #define MCA_BANKS_MASK 0xff @@ -45,6 +50,9 @@ #define ENERGY_POLICY_POWERSAVE 15 #define IA32_PACKAGE_THERM_INTERRUPT 0x1b2 #define IA32_PLATFORM_DCA_CAP 0x1f8 +#define SMRR_PHYSBASE_MSR 0x1F2 +#define SMRR_PHYSMASK_MSR 0x1F3 +#define IA32_PLATFORM_DCA_CAP 0x1f8 #define IA32_PAT 0x277 #define IA32_MC0_CTL 0x400 #define IA32_MC0_STATUS 0x401 @@ -65,6 +73,8 @@ #define MCA_STATUS_LO_ERRCODE_EXT_SH 16 #define MCA_STATUS_LO_ERRCODE_EXT_MASK (0x3f << MCA_STATUS_LO_ERRCODE_EXT_SH) #define MCA_STATUS_LO_ERRCODE_MASK (0xffff << 0) +#define IA32_VMX_BASIC_MSR 0x480 +#define IA32_VMX_MISC_MSR 0x485 #define MC0_ADDR 0x402 #define MC0_MISC 0x403 #define MC0_CTL_MASK 0xC0010044 diff --git a/src/include/cpu/x86/smm.h b/src/include/cpu/x86/smm.h index cf107b121a..9efe2e04eb 100644 --- a/src/include/cpu/x86/smm.h +++ b/src/include/cpu/x86/smm.h @@ -64,6 +64,9 @@ extern unsigned char _binary_smm_end[]; struct smm_runtime { u32 smbase; u32 save_state_size; + u32 num_cpus; + /* STM's 32bit entry into SMI handler */ + u32 start32_offset; /* The apic_id_to_cpu provides a mapping from APIC id to CPU number. * The CPU number is indicated by the index into the array by matching * the default APIC id and value at the index. The stub loader diff --git a/src/security/intel/Kconfig b/src/security/intel/Kconfig index a4525e7b9b..aa24e8ac68 100644 --- a/src/security/intel/Kconfig +++ b/src/security/intel/Kconfig @@ -14,3 +14,4 @@ ## source "src/security/intel/txt/Kconfig" +source "src/security/intel/stm/Kconfig" diff --git a/src/security/intel/Makefile.inc b/src/security/intel/Makefile.inc index 9388d3f798..e00802ad06 100644 --- a/src/security/intel/Makefile.inc +++ b/src/security/intel/Makefile.inc @@ -1 +1,2 @@ subdirs-y += txt +subdirs-y += stm diff --git a/src/security/intel/stm/Kconfig b/src/security/intel/stm/Kconfig new file mode 100644 index 0000000000..a74eba8522 --- /dev/null +++ b/src/security/intel/stm/Kconfig @@ -0,0 +1,49 @@ + + +config STM + bool "Enable STM" + default n + depends on SMM_TSEG + select USE_BLOBS + + help + Enabling the STM will load a simple hypervisor into SMM that will + restrict the actions of the SMI handler, which is the part of BIOS + that functions in system management mode (SMM). The kernel can + configure the STM to prevent the SMI handler from accessing platform + resources. + The STM closes a vulnerability in Intel TXT (D-RTM) + The SMI handler provides a list of platform resources that it + requires access to the STM during STM startup, which the kernel + cannot override. + An additional capability, called STM-PE, provides a protected + execution capability that allows modules to be executed without + observation and interference. Examples of usage include kernel + introspection and virtualized trusted platform module (vTPM). + Requirement: SMM must be enabled and there must be sufficient room + within the TSEG to fit the MSEG. + +if STM + +menu "SMI Transfer Monitor (STM)" + +config MSEG_SIZE + hex "mseg size" + default 0x400000 + help + STM only - 0x100000 + STM/PE - 0x300000+ depending on the amount of memory needed + for the protected execution virtual + machine (VM/PE) + +config BIOS_RESOURCE_LIST_SIZE + hex "bios_resource_list_size" + default 0x1000 + +config STM_BINARY_FILE + string "STM binary file" + default "3rdparty/blobs/cpu/intel/stm/stm.bin" + +endmenu #STM + +endif diff --git a/src/security/intel/stm/Makefile.inc b/src/security/intel/stm/Makefile.inc new file mode 100644 index 0000000000..1a23fe97f2 --- /dev/null +++ b/src/security/intel/stm/Makefile.inc @@ -0,0 +1,10 @@ + +# put the stm where it can be found + +cbfs-files-$(CONFIG_STM) += stm.bin +stm.bin-file := $(CONFIG_STM_BINARY_FILE) +stm.bin-type := raw + +ramstage-$(CONFIG_STM) += SmmStm.c +ramstage-$(CONFIG_STM) += StmPlatformSmm.c +ramstage-$(CONFIG_STM) += StmPlatformResource.c diff --git a/src/security/intel/stm/SmmStm.c b/src/security/intel/stm/SmmStm.c new file mode 100644 index 0000000000..f23be70217 --- /dev/null +++ b/src/security/intel/stm/SmmStm.c @@ -0,0 +1,691 @@ +/* @file + * SMM STM support + * + * Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved. + * + * This program and the accompanying materials are licensed and made available + * under the terms and conditions of the BSD License which accompanies this + * distribution. The full text of the license may be found at + * http://opensource.org/licenses/bsd-license.php. + * + * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR + * IMPLIED. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#define TXT_EVTYPE_BASE 0x400 +#define TXT_EVTYPE_STM_HASH (TXT_EVTYPE_BASE + 14) + +#define RDWR_ACCS 3 +#define FULL_ACCS 7 + +#define SIZE_4KB 0x00001000 +#define SIZE_4MB 0x00400000 + +#define PTP_SIZE SIZE_4KB + +#define IA32_PG_P (1 << 0) +#define IA32_PG_RW (1 << 1) +#define IA32_PG_PS (1 << 7) + +#define STM_PAGE_SHIFT 12 +#define STM_PAGE_MASK 0xFFF +#define STM_SIZE_TO_PAGES(a) \ + (((a) >> STM_PAGE_SHIFT) + (((a)&STM_PAGE_MASK) ? 1 : 0)) +#define STM_PAGES_TO_SIZE(a) ((a) << STM_PAGE_SHIFT) + +#define STM_ACCESS_DENIED 15 +#define STM_UNSUPPORTED 3 + +#define STM_BUFFER_TOO_SMALL 1 + +#define STM_SM_MONITOR_STATE_ENABLED 1 + +typedef struct { + + uint64_t vmcs_revision_id : 31; + uint64_t always_zero : 1; + uint64_t vmcs_size : 13; + uint64_t reserved1 : 3; + uint64_t vmxon_add_width : 1; + uint64_t stm_supported : 1; + uint64_t vmcs_memory_type : 4; + uint64_t in_out_reporting : 1; + uint64_t may_clear_defaults : 1; + uint64_t reserved2 : 8; +} VMX_BASIC_MSR_BITS; + +typedef union { + VMX_BASIC_MSR_BITS bits; + uint64_t uint64; + msr_t msr; +} VMX_BASIC_MSR; + +typedef struct { + uint64_t valid : 1; + uint64_t reserved1 : 1; + uint64_t vmx_off_blockSmi : 1; + uint64_t reserved2 : 9; + uint64_t mseg_address : 20; + uint64_t reserved3 : 32; +} SMM_MONITOR_CTL_MSR_BITS; + +extern 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; + +typedef union { + SMM_MONITOR_CTL_MSR_BITS bits; + uint64_t uint64; + msr_t msr; +} SMM_MONITOR_CTL_MSR; + +// Template of STM_RSC_END structure for copying. + +STM_RSC_END m_rsc_end_node = { + {END_OF_RESOURCES, sizeof(STM_RSC_END)}, +}; + +uint8_t *m_stm_resources_ptr = NULL; +uint32_t m_stm_resource_total_size = 0x0; +uint32_t m_stm_resource_size_used = 0x0; +uint32_t m_stm_resource_size_available = 0x0; + +uint8_t *stm_resource_heap = NULL; + +uint32_t m_stm_state = 0; + +/* + * Handle single Resource to see if it can be merged into Record. + * + * @param resource A pointer to resource node to be added + * @param record A pointer to record node to be merged + * + * @retval true resource handled + * @retval false resource is not handled + */ + +static bool handle_single_resource(STM_RSC *resource, STM_RSC *record) +{ + uint64_t resource_lo = 0; + uint64_t resource_hi = 0; + uint64_t record_lo = 0; + uint64_t record_hi = 0; + + // Calling code is responsible for making sure that + // Resource->Header.RscType == (*Record)->Header.RscType + // thus we use just one of them as switch variable. + + switch (resource->header.rsc_type) { + case MEM_RANGE: + case MMIO_RANGE: + resource_lo = resource->mem.base; + resource_hi = resource->mem.base + resource->mem.length; + record_lo = record->mem.base; + record_hi = record->mem.base + record->mem.length; + if (resource->mem.rwx_attributes + != record->mem.rwx_attributes) { + if ((resource_lo == record_lo) + && (resource_hi == record_hi)) { + record->mem.rwx_attributes = + resource->mem.rwx_attributes + | record->mem.rwx_attributes; + return true; + } else { + return false; + } + } + break; + case IO_RANGE: + case TRAPPED_IO_RANGE: + resource_lo = (uint64_t)resource->io.base; + resource_hi = (uint64_t)resource->io.base + + (uint64_t)resource->io.length; + record_lo = (uint64_t)record->io.base; + record_hi = + (uint64_t)record->io.base + (uint64_t)record->io.length; + break; + case PCI_CFG_RANGE: + if ((resource->pci_cfg.originating_bus_number + != record->pci_cfg.originating_bus_number) + || (resource->pci_cfg.last_node_index + != record->pci_cfg.last_node_index)) + return false; + + if (memcmp(resource->pci_cfg.pci_device_path, + record->pci_cfg.pci_device_path, + sizeof(STM_PCI_DEVICE_PATH_NODE) + * (resource->pci_cfg.last_node_index + 1)) + != 0) { + return false; + } + resource_lo = (uint64_t)resource->pci_cfg.base; + resource_hi = (uint64_t)resource->pci_cfg.base + + (uint64_t)resource->pci_cfg.length; + record_lo = (uint64_t)record->pci_cfg.base; + record_hi = (uint64_t)record->pci_cfg.base + + (uint64_t)record->pci_cfg.length; + if (resource->pci_cfg.rw_attributes + != record->pci_cfg.rw_attributes) { + if ((resource_lo == record_lo) + && (resource_hi == record_hi)) { + record->pci_cfg.rw_attributes = + resource->pci_cfg.rw_attributes + | record->pci_cfg.rw_attributes; + return true; + } else { + return false; + } + } + break; + case MACHINE_SPECIFIC_REG: + + // Special case - merge MSR masks in place. + if (resource->msr.msr_index != record->msr.msr_index) + return false; + record->msr.read_mask |= resource->msr.read_mask; + record->msr.write_mask |= resource->msr.write_mask; + return true; + default: + return false; + } + + // If resources are disjoint + if ((resource_hi < record_lo) || (resource_lo > record_hi)) + return false; + + // If resource is consumed by record. + if ((resource_lo >= record_lo) && (resource_hi <= record_hi)) + return true; + + // Resources are overlapping. + // Resource and record are merged. + resource_lo = (resource_lo < record_lo) ? resource_lo : record_lo; + resource_hi = (resource_hi > record_hi) ? resource_hi : record_hi; + + switch (resource->header.rsc_type) { + case MEM_RANGE: + case MMIO_RANGE: + record->mem.base = resource_lo; + record->mem.length = resource_hi - resource_lo; + break; + case IO_RANGE: + case TRAPPED_IO_RANGE: + record->io.base = (uint64_t)resource_lo; + record->io.length = (uint64_t)(resource_hi - resource_lo); + break; + case PCI_CFG_RANGE: + record->pci_cfg.base = (uint64_t)resource_lo; + record->pci_cfg.length = (uint64_t)(resource_hi - resource_lo); + break; + default: + return false; + } + + return true; +} + +/* + * Add resource node. + * + * @param Resource A pointer to resource node to be added + */ +static void add_single_resource(STM_RSC *resource) +{ + STM_RSC *record; + + record = (STM_RSC *)m_stm_resources_ptr; + + while (true) { + if (record->header.rsc_type == END_OF_RESOURCES) + break; + + // Go to next record if resource and record types don't match. + if (resource->header.rsc_type != record->header.rsc_type) { + record = (STM_RSC *)((void *)record + + record->header.length); + continue; + } + + // Record is handled inside of procedure - don't adjust. + if (handle_single_resource(resource, record)) + return; + record = (STM_RSC *)((void *)record + record->header.length); + } + + // Add resource to the end of area. + memcpy(m_stm_resources_ptr + m_stm_resource_size_used + - sizeof(m_rsc_end_node), + resource, resource->header.length); + memcpy(m_stm_resources_ptr + m_stm_resource_size_used + - sizeof(m_rsc_end_node) + resource->header.length, + &m_rsc_end_node, sizeof(m_rsc_end_node)); + m_stm_resource_size_used += resource->header.length; + m_stm_resource_size_available = + m_stm_resource_total_size - m_stm_resource_size_used; +} + +/* + * Add resource list. + * + * @param resource_list A pointer to resource list to be added + * @param num_entries Optional number of entries. + * If 0, list must be terminated by END_OF_RESOURCES. + */ +static void add_resource(STM_RSC *resource_list, uint32_t num_entries) +{ + uint32_t count; + uint32_t index; + STM_RSC *resource; + + if (num_entries == 0) + count = 0xFFFFFFFF; + else + count = num_entries; + + resource = resource_list; + + for (index = 0; index < count; index++) { + if (resource->header.rsc_type == END_OF_RESOURCES) + return; + add_single_resource(resource); + resource = + (STM_RSC *)((void *)resource + resource->header.length); + } +} + +/* + * Validate resource list. + * + * @param resource_list A pointer to resource list to be added + * @param num_entries Optional number of entries. + * If 0, list must be terminated by END_OF_RESOURCES. + * + * @retval true resource valid + * @retval false resource invalid + */ +static bool validate_resource(STM_RSC *resource_list, uint32_t num_entries) +{ + uint32_t count; + uint32_t index; + STM_RSC *resource; + uint32_t sub_index; + + // If NumEntries == 0 make it very big. Scan will be terminated by + // END_OF_RESOURCES. + if (num_entries == 0) + count = 0xFFFFFFFF; + else + count = num_entries; + + // Start from beginning of resource list. + resource = resource_list; + + for (index = 0; index < count; index++) { + printk(BIOS_DEBUG, "STM: %s (%u) - RscType(%x) length(0x%x)\n", + __func__, + index, + resource->header.rsc_type, + resource->header.length); + // Validate resource. + switch (resource->header.rsc_type) { + case END_OF_RESOURCES: + if (resource->header.length != sizeof(STM_RSC_END)) + return false; + + // If we are passed actual number of resources to add, + // END_OF_RESOURCES structure between them is considered + // an error. If NumEntries == 0 END_OF_RESOURCES is a + // termination. + if (num_entries != 0) + return false; + + // If NumEntries == 0 and list reached end - return + // success. + return true; + + case MEM_RANGE: + case MMIO_RANGE: + printk(BIOS_DEBUG, + "STM: %s - MEM (0x%0llx, 0x%0llx)\n", + __func__, + resource->mem.base, + resource->mem.length); + + if (resource->header.length != sizeof(STM_RSC_MEM_DESC)) + return false; + + if (resource->mem.rwx_attributes > FULL_ACCS) + return false; + break; + + case IO_RANGE: + case TRAPPED_IO_RANGE: + if (resource->header.length != sizeof(STM_RSC_IO_DESC)) + return false; + + if ((resource->io.base + resource->io.length) > 0xFFFF) + return false; + break; + + case PCI_CFG_RANGE: + printk(BIOS_DEBUG, + "STM: %s - PCI (0x%02x, 0x%08x, 0x%02x, 0x%02x)\n", + __func__, + resource->pci_cfg.originating_bus_number, + resource->pci_cfg.last_node_index, + resource->pci_cfg.pci_device_path[0].pci_device, + resource->pci_cfg.pci_device_path[0] + .pci_function); + if (resource->header.length + != sizeof(STM_RSC_PCI_CFG_DESC) + + (sizeof(STM_PCI_DEVICE_PATH_NODE) + * resource->pci_cfg.last_node_index)) + return false; + for (sub_index = 0; + sub_index <= resource->pci_cfg.last_node_index; + sub_index++) { + if ((resource->pci_cfg + .pci_device_path[sub_index] + .pci_device + > 0x1F) + || (resource->pci_cfg + .pci_device_path[sub_index] + .pci_function + > 7)) + return false; + } + if ((resource->pci_cfg.base + resource->pci_cfg.length) + > 0x1000) + return false; + break; + + case MACHINE_SPECIFIC_REG: + if (resource->header.length != sizeof(STM_RSC_MSR_DESC)) + return false; + break; + + default: + printk(BIOS_DEBUG, "STM: %s - Unknown RscType(%x)\n", + __func__, resource->header.rsc_type); + return false; + } + resource = + (STM_RSC *)((void *)resource + resource->header.length); + } + return true; +} + +/* + * Get resource list. + * EndResource is excluded. + * + * @param resou rce_list A pointer to resource list to be added + * @param num_entries Optional number of entries. + * If 0, list must be terminated by END_OF_RESOURCES. + * + * @retval true resource valid + * @retval false resource invalid + */ +static uint32_t get_resource_size(STM_RSC *resource_list, uint32_t num_entries) +{ + uint32_t count; + uint32_t index; + STM_RSC *resource; + + resource = resource_list; + + // If NumEntries == 0 make it very big. Scan will be terminated by + // END_OF_RESOURCES. + if (num_entries == 0) + count = 0xFFFFFFFF; + else + count = num_entries; + + // Start from beginning of resource list. + resource = resource_list; + + for (index = 0; index < count; index++) { + if (resource->header.rsc_type == END_OF_RESOURCES) + break; + resource = + (STM_RSC *)((void *)resource + resource->header.length); + } + return (uint32_t)((uint32_t)resource - (uint32_t)resource_list); +} + +/* + * Add resources in list to database. Allocate new memory areas as needed. + * + * @param resource_list A pointer to resource list to be added + * @param num_entries Optional number of entries. + * If 0, list must be terminated by END_OF_RESOURCES. + * + * @retval SUCCESS If resources are added + * @retval INVALID_PARAMETER If nested procedure detected resource failure + * @retval OUT_OF_RESOURCES If nested procedure returned it and we cannot + * allocate more areas. + */ +int add_pi_resource(STM_RSC *resource_list, uint32_t num_entries) +{ + size_t resource_size; + + printk(BIOS_DEBUG, "STM: %s - Enter\n", __func__); + + if (!validate_resource(resource_list, num_entries)) + return -1; // INVALID_PARAMETER; + + resource_size = get_resource_size(resource_list, num_entries); + printk(BIOS_DEBUG, "STM: ResourceSize - 0x%08lx\n", resource_size); + if (resource_size == 0) + return -1; // INVALID_PARAMETER; + + if (m_stm_resources_ptr == NULL) { + + // Copy EndResource for initialization + m_stm_resources_ptr = stm_resource_heap; + m_stm_resource_total_size = CONFIG_BIOS_RESOURCE_LIST_SIZE; + memset(m_stm_resources_ptr, 0, CONFIG_BIOS_RESOURCE_LIST_SIZE); + + memcpy(m_stm_resources_ptr, &m_rsc_end_node, + sizeof(m_rsc_end_node)); + m_stm_resource_size_used = sizeof(m_rsc_end_node); + m_stm_resource_size_available = + m_stm_resource_total_size - sizeof(m_rsc_end_node); + wbinvd(); // force to memory + + } else { + if (m_stm_resource_size_available < resource_size) { + printk(BIOS_DEBUG, + "STM: ERROR - not enough space for SMM resource list\n"); + return -1; // OUT_OF_RESOURCES + } + } + + // Check duplication + add_resource(resource_list, num_entries); + + return 0; // SUCCESS; +} + +/* + * Delete resources in list to database. + * + * @param resource_list A pointer to resource list to be deleted + * NULL means delete all resources. + * @param num_entries Optional number of entries. + * If 0, list must be terminated by END_OF_RESOURCES. + * + * @retval SUCCESS If resources are deleted + * @retval INVALID_PARAMETER If nested procedure detected resource failure + */ +int32_t delete_pi_resource(STM_RSC *resource_list, uint32_t num_entries) +{ + if (resource_list != NULL) { + // ASSERT (false); + return -1; // UNSUPPORTED; + } + + // Delete all + memcpy(m_stm_resources_ptr, &m_rsc_end_node, sizeof(m_rsc_end_node)); + m_stm_resource_size_used = sizeof(m_rsc_end_node); + m_stm_resource_size_available = + m_stm_resource_total_size - sizeof(m_rsc_end_node); + return 0; // SUCCESS; +} + +/* + * Get BIOS resources. + * + * @param resource_list A pointer to resource list to be filled + * @param resource_size On input it means size of resource list input. + * On output it means size of resource list filled, + * or the size of resource list to be filled if size is + * too small. + * + * @retval SUCCESS If resources are returned. + * @retval BUFFER_TOO_SMALL If resource list buffer is too small to hold + * the whole resource list. + */ +int32_t get_pi_resource(STM_RSC *resource_list, uint32_t *resource_size) +{ + if (*resource_size < m_stm_resource_size_used) { + *resource_size = (uint32_t)m_stm_resource_size_used; + return -1; // BUFFER_TOO_SMALL; + } + + memcpy(resource_list, m_stm_resources_ptr, m_stm_resource_size_used); + *resource_size = (uint32_t)m_stm_resource_size_used; + return 0; // SUCCESS; +} + +/* + * Get 4K page aligned VMCS size. + * @return 4K page aligned VMCS size + */ +static uint32_t get_vmcs_size(void) +{ + uint32_t this_vmcs_size; + VMX_BASIC_MSR msr_data64; + int stm_support; + + msr_data64.msr = rdmsr(IA32_VMX_BASIC_MSR); + + this_vmcs_size = msr_data64.bits.vmcs_size; + stm_support = msr_data64.bits.stm_supported; + printk(BIOS_DEBUG, "STM: %s: Size %d StmSupport %d\n", __func__, + this_vmcs_size, stm_support); + + // VMCS require 0x1000 alignment + this_vmcs_size = STM_PAGES_TO_SIZE(STM_SIZE_TO_PAGES(this_vmcs_size)); + + return this_vmcs_size; +} + +/* + * Create 4G page table for STM. + * 2M PTEs for x86_64 or 2M PTEs for x86_32. + * + * @param pageable_base The page table base in MSEG + */ +void stm_gen_4g_pagetable_x64(uint32_t pagetable_base) +{ + uint32_t index; + uint32_t sub_index; + uint64_t *pde; + uint64_t *pte; + uint64_t *pml4; + + pml4 = (uint64_t *)(uint32_t)pagetable_base; + pagetable_base += PTP_SIZE; + *pml4 = pagetable_base | IA32_PG_RW | IA32_PG_P; + + pde = (uint64_t *)(uint32_t)pagetable_base; + pagetable_base += PTP_SIZE; + pte = (uint64_t *)(uint32_t)pagetable_base; + + for (index = 0; index < 4; index++) { + *pde = pagetable_base | IA32_PG_RW | IA32_PG_P; + pde++; + pagetable_base += PTP_SIZE; + + for (sub_index = 0; sub_index < SIZE_4KB / sizeof(*pte); + sub_index++) { + *pte = (((index << 9) + sub_index) << 21) | IA32_PG_PS + | IA32_PG_RW | IA32_PG_P; + pte++; + } + } +} + +/* + * Check STM image size. + * + * @param stm_image STM image + * @param stm_imageSize STM image size + * + * @retval true check pass + * @retval false check fail + */ + +bool stm_check_stm_image(void *stm_image, uint32_t stm_imagesize) +{ + uint32_t min_mseg_size; + STM_HEADER *stm_header; + + stm_header = (STM_HEADER *)stm_image; + + // Get Minimal required Mseg size + min_mseg_size = (STM_PAGES_TO_SIZE(STM_SIZE_TO_PAGES( + stm_header->sw_stm_hdr.static_image_size)) + + stm_header->sw_stm_hdr.additional_dynamic_memory_size + + (stm_header->sw_stm_hdr.per_proc_dynamic_memory_size + + get_vmcs_size() * 2) + * mp_state.cpu_count); + if (min_mseg_size < stm_imagesize) + min_mseg_size = stm_imagesize; + + if (stm_header->hw_stm_hdr.cr3_offset + >= stm_header->sw_stm_hdr.static_image_size) { + + // We will create page table, just in case that SINIT does not + // create it. + if (min_mseg_size < stm_header->hw_stm_hdr.cr3_offset + + STM_PAGES_TO_SIZE(6)) { + min_mseg_size = stm_header->hw_stm_hdr.cr3_offset + + STM_PAGES_TO_SIZE(6); + } + } + + // Check if it exceeds MSEG size + if (min_mseg_size > CONFIG_MSEG_SIZE) + return false; + + return true; +} + +/* + * This function return BIOS STM resource. + * Produced by SmmStm. + * Comsumed by SmmMpService when Init. + * + * @return BIOS STM resource + */ +void *get_stm_resource(void) +{ + return m_stm_resources_ptr; +} diff --git a/src/security/intel/stm/SmmStm.h b/src/security/intel/stm/SmmStm.h new file mode 100644 index 0000000000..4f72816cae --- /dev/null +++ b/src/security/intel/stm/SmmStm.h @@ -0,0 +1,120 @@ +/* @file + * SMM STM support + * + * Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved. + * This program and the accompanying materials are licensed and made + * available under the terms and conditions of the BSD License which + * accompanies this distribution. The full text of the license may + * be found at http://opensource.org/licenses/bsd-license.php. + * + * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED + * + */ + +#ifndef _SMM_STM_H_ +#define _SMM_STM_H_ + +#include +#include "StmApi.h" + +/* + * Load STM image. + * + * @retval SUCCESS STM is loaded to MSEG + * @retval BUFFER_TOO_SMALL MSEG is too small + * @retval UNSUPPORTED MSEG is not enabled + */ +int load_stm_image(uintptr_t mseg); + +void stm_setup( + uintptr_t mseg, int cpu, int num_cpus, uintptr_t smbase, + uintptr_t smbase_base, uint32_t offset32); + +/* + * Add resources in list to database. Allocate new memory areas as needed. + * + * @param resource_list A pointer to resource list to be added + * @param num_entries Optional number of entries. + * If 0, list must be terminated by END_OF_RESOURCES. + * + * @retval SUCCESS If resources are added + * @retval INVALID_PARAMETER If nested procedure detected resource failure + * @retval OUT_OF_RESOURCES If nested procedure returned it and we cannot + * allocate more areas. + */ +int add_pi_resource(STM_RSC *resource_list, uint32_t num_entries); + +/* + * Delete resources in list to database. + * + * @param resource_list A pointer to resource list to be deleted + * NULL means delete all resources. + * @param num_entries Optional number of entries. + * If 0, list must be terminated by END_OF_RESOURCES. + * + * @retval SUCCESS If resources are deleted + * @retval NVALID_PARAMETER If nested procedure detected resource fail + */ +int delete_pi_resource(STM_RSC *resource_list, uint32_t num_entries); + +/* + * Get BIOS resources. + * + * @param resource_list A pointer to resource list to be filled + * @param resource_size On input it means size of resource list input. + * On output it means size of resource list filled, + * or the size of resource list to be filled if + * size is too small. + * + * @retval SUCCESS If resources are returned. + * @retval BUFFER_TOO_SMALL If resource list buffer is too small to + * hold the whole resources. + */ +int get_pi_resource(STM_RSC *resource_list, uint32_t *resource_size); + +/* + * This function notifies the STM of a resource change. + * + * @param stm_resource BIOS STM resource + */ +void notify_stm_resource_change(void *stm_resource); + +/* + * This function returns the pointer to the STM BIOS resource list. + * + * @return BIOS STM resource + */ +void *get_stm_resource(void); + +void setup_smm_descriptor(void *smbase, void *base_smbase, int32_t apic_id, + int32_t entry32_off); + +/* + * Check STM image size. + * + * @param stm_image STM image + * @param stm_image_size STM image size + * + * @retval true check pass + * @retval false check fail + */ +bool stm_check_stm_image(void *stm_image, uint32_t stm_image_size); + +/* + * Create 4G page table for STM. + * 4M Non-PAE page table in IA32 version. + * + * @param page_table_base The page table base in MSEG + */ +void stm_gen_4g_pagetable_ia32(uint32_t pagetable_base); + +/* + * Create 4G page table for STM. + * 2M PAE page table in X64 version. + * + * @param pagetable_base The page table base in MSEG + */ +void stm_gen_4g_pagetable_x64(uint32_t pagetable_base); + +#endif diff --git a/src/security/intel/stm/StmApi.h b/src/security/intel/stm/StmApi.h new file mode 100644 index 0000000000..342ceeacf6 --- /dev/null +++ b/src/security/intel/stm/StmApi.h @@ -0,0 +1,726 @@ +/* @file + * STM API definition + * + * Copyright (c) 2015, Intel Corporation. All rights reserved. + * This program and the accompanying materials are licensed and made available + * under the terms and conditions of the BSD License which accompanies this + * distribution. The full text of the license may be found at + * http://opensource.org/licenses/bsd-license.php. + * + * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, + * EITHER EXPRESS OR IMPLIED. + * + */ + +#ifndef _STM_API_H_ +#define _STM_API_H_ + +#include + +// definition in STM spec + +#define STM_SPEC_VERSION_MAJOR 1 +#define STM_SPEC_VERSION_MINOR 0 + +#pragma pack(push, 1) + +#define STM_HARDWARE_FIELD_FILL_TO_2K (2048 - sizeof(uint32_t) * 8) +typedef struct { + uint32_t stm_header_revision; + uint32_t monitor_features; + uint32_t gdtr_limit; + uint32_t gdtr_base_offset; + uint32_t cs_selector; + uint32_t eip_offset; + uint32_t esp_offset; + uint32_t cr3_offset; + uint8_t reserved[STM_HARDWARE_FIELD_FILL_TO_2K]; +} HARDWARE_STM_HEADER; + +#define STM_FEATURES_IA32E 0x1 + +typedef struct { + uint32_t intel_64mode_supported : 1; + uint32_t ept_supported : 1; + uint32_t mbz : 30; +} STM_FEAT; + +typedef struct { + uint8_t stm_spec_ver_major; + uint8_t stm_pec_ver_minor; + uint16_t mbz; + uint32_t static_image_size; + uint32_t per_proc_dynamic_memory_size; + uint32_t additional_dynamic_memory_size; + STM_FEAT stm_features; + uint32_t number_of_rev_ids; + uint32_t stm_smm_rev_id[1]; + + // The total STM_HEADER should be 4K. +} SOFTWARE_STM_HEADER; + +typedef struct { + HARDWARE_STM_HEADER hw_stm_hdr; + SOFTWARE_STM_HEADER sw_stm_hdr; +} STM_HEADER; + +#define SHA1 1 +#define SHA256 2 +typedef struct { + uint64_t bios_component_base; + uint32_t image_size; + uint32_t hash_algorithm; // SHA1 or SHA256 + uint8_t hash[32]; +} TXT_BIOS_COMPONENT_STATUS; + +#define PAGE_SIZE 4096 +typedef struct { + uint32_t image_size; + uint32_t reserved; + uint64_t image_page_base[1]; //[NumberOfPages]; +} TXT_BIOS_COMPONENT_UPDATE; + +typedef struct { + uint64_t spe_rip; + uint64_t spe_rsp; + uint16_t spe_ss; + uint16_t page_violation_exception : 1; + uint16_t msr_violation_exception : 1; + uint16_t register_violation_exception : 1; + uint16_t io_violation_exception : 1; + uint16_t pci_violation_exception : 1; + uint16_t reserved1 : 11; + uint32_t reserved2; +} STM_PROTECTION_EXCEPTION_HANDLER; + +typedef struct { + uint8_t execution_disable_outside_smrr : 1; + uint8_t intel_64mode : 1; + uint8_t cr4_pae : 1; + uint8_t cr4_pse : 1; + uint8_t reserved1 : 4; +} STM_SMM_ENTRY_STATE; + +typedef struct { + uint8_t smram_to_vmcs_restore_required : 1; // BIOS restore hint + uint8_t reinitialize_vmcs_required : 1; // BIOS request + uint8_t reserved2 : 6; +} STM_SMM_RESUME_STATE; + +typedef struct { + uint8_t domain_type : 4; // STM input to BIOS on each SM + uint8_t x_state_policy : 2; // STM input to BIOS on each SMI + uint8_t ept_enabled : 1; + uint8_t reserved3 : 1; +} STM_SMM_STATE; + +typedef struct { + uint64_t signature; + uint16_t size; + uint8_t smm_descriptor_ver_major; + uint8_t smm_descriptor_ver_minor; + uint32_t local_apic_id; + STM_SMM_ENTRY_STATE smm_entry_state; + STM_SMM_RESUME_STATE smm_resume_state; + STM_SMM_STATE stm_smm_state; + uint8_t reserved4; + uint16_t smm_cs; + uint16_t smm_ds; + uint16_t smm_ss; + uint16_t smm_other_segment; + uint16_t smm_tr; + uint16_t reserved5; + uint64_t smm_cr3; + uint64_t smm_stm_setup_rip; + uint64_t smm_stm_teardown_rip; + uint64_t smm_smi_handler_rip; + uint64_t smm_smi_handler_rsp; + uint64_t smm_gdt_ptr; + uint32_t smm_gdt_size; + uint32_t required_stm_smm_rev_id; + STM_PROTECTION_EXCEPTION_HANDLER stm_protection_exception_handler; + uint64_t reserved6; + uint64_t bios_hw_resource_requirements_ptr; + // extend area + uint64_t acpi_rsdp; + uint8_t physical_address_bits; +} TXT_PROCESSOR_SMM_DESCRIPTOR; + +#define TXT_PROCESSOR_SMM_DESCRIPTOR_SIGNATURE "TXTPSSIG" +#define TXT_PROCESSOR_SMM_DESCRIPTOR_VERSION_MAJOR 1 +#define TXT_PROCESSOR_SMM_DESCRIPTOR_VERSION_MINOR 0 + +#define SMM_PSD_OFFSET 0xfb00 + +typedef enum { + TxtSmmPageViolation = 1, + TxtSmmMsrViolation, + TxtSmmRegisterViolation, + TxtSmmIoViolation, + TxtSmmPciViolation +} TXT_SMM_PROTECTION_EXCEPTION_TYPE; + +typedef struct { + uint32_t rdi; + uint32_t rsi; + uint32_t rbp; + uint32_t rdx; + uint32_t rcx; + uint32_t rbx; + uint32_t rax; + uint32_t cr3; + uint32_t cr2; + uint32_t cr0; + uint32_t vmcs_exit_instruction_info; + uint32_t vmcs_exit_instruction_length; + uint64_t vmcs_exit_qualification; + uint32_t error_code; // TXT_SMM_PROTECTION_EXCEPTION_TYPE + uint32_t rip; + uint32_t cs; + uint32_t rflags; + uint32_t rsp; + uint32_t ss; +} STM_PROTECTION_EXCEPTION_STACK_FRAME_IA32; + +typedef struct { + uint64_t r15; + uint64_t r14; + uint64_t r13; + uint64_t r12; + uint64_t r11; + uint64_t r10; + uint64_t r9; + uint64_t r8; + uint64_t rdi; + uint64_t rsi; + uint64_t rbp; + uint64_t rdx; + uint64_t rcx; + uint64_t rbx; + uint64_t rax; + uint64_t cr8; + uint64_t cr3; + uint64_t cr2; + uint64_t cr0; + uint64_t vmcs_exit_instruction_info; + uint64_t vmcs_exit_instruction_length; + uint64_t vmcs_exit_qualification; + uint64_t error_code; // TXT_SMM_PROTECTION_EXCEPTION_TYPE + uint64_t rip; + uint64_t cs; + uint64_t rflags; + uint64_t rsp; + uint64_t ss; +} STM_PROTECTION_EXCEPTION_STACK_FRAME_X64; + +typedef union { + STM_PROTECTION_EXCEPTION_STACK_FRAME_IA32 *ia32_stack_frame; + STM_PROTECTION_EXCEPTION_STACK_FRAME_X64 *x64_stack_frame; +} STM_PROTECTION_EXCEPTION_STACK_FRAME; + +#define STM_SMM_REV_ID 0x80010100 + +typedef struct _STM_SMM_CPU_STATE { // Writable? + uint8_t reserved1[0x1d0]; // fc00h + uint32_t gdt_base_hi_dword; // fdd0h : NO + uint32_t ldt_base_hi_dword; // fdd4h : NO + uint32_t idt_base_hi_dword; // fdd8h : NO + uint8_t reserved2[0x4]; // fddch + uint64_t io_rdi; // fde0h : NO + // - restricted + uint64_t io_eip; // fde8h : YES + uint64_t io_rcx; // fdf0h : NO + // - restricted + uint64_t io_rsi; // fdf8h : NO + // - restricted + uint8_t reserved3[0x40]; // fe00h + uint32_t cr4; // fe40h : NO + uint8_t reserved4[0x48]; // fe44h + uint32_t gdt_base_lo_dword; // fe8ch : NO + uint32_t gdt_limit; // fe90h : NO + // - RESTRICTED + uint32_t idt_base_lo_dword; // fe94h : NO + uint32_t idt_limit; // fe98h : NO + // - RESTRICTED + uint32_t ldt_base_lo_dword; // fe9ch : NO + uint32_t ldt_limit; // fea0h : NO + // - RESTRICTED + uint32_t ldt_info; // fea4h : NO + // - RESTRICTED + uint8_t reserved5[0x30]; // fea8h + uint64_t eptp; // fed8h : NO + uint32_t enabled_ept; // fee0h : NO + uint8_t reserved6[0x14]; // fee4h + uint32_t smbase; // fef8h : YES + // - NO for STM + uint32_t smm_rev_id; // fefch : NO + uint16_t io_restart; // ff00h : YES + uint16_t auto_halt_restart; // ff02h : YES + uint8_t reserved7[0x18]; // ff04h + uint64_t r15; // ff1ch : YES + uint64_t r14; // ff24h : YES + uint64_t r13; // ff2ch : YES + uint64_t r12; // ff34h : YES + uint64_t r11; // ff3ch : YES + uint64_t r10; // ff44h : YES + uint64_t r9; // ff4ch : YES + uint64_t r8; // ff54h : YES + uint64_t rax; // ff5ch : YES + uint64_t rcx; // ff64h : YES + uint64_t rdx; // ff6ch : YES + uint64_t rbx; // ff74h : YES + uint64_t rsp; // ff7ch : YES + uint64_t rbp; // ff84h : YES + uint64_t rsi; // ff8ch : YES + uint64_t rdi; // ff94h : YES + uint64_t io_mem_addr; // ff9ch : NO + uint32_t io_misc; // ffa4h : NO + uint32_t es; // ffa8h : NO + uint32_t cs; // ffach : NO + uint32_t ss; // ffb0h : NO + uint32_t ds; // ffb4h : NO + uint32_t fs; // ffb8h : NO + uint32_t gs; // ffbch : NO + uint32_t ldtr; // ffc0h : NO + uint32_t tr; // ffc4h : NO + uint64_t dr7; // ffc8h : NO + uint64_t dr6; // ffd0h : NO + uint64_t rip; // ffd8h : YES + uint64_t ia32_efer; // ffe0h : YES + // - NO for STM + uint64_t rflags; // ffe8h : YES + uint64_t cr3; // fff0h : NO + uint64_t cr0; // fff8h : NO +} STM_SMM_CPU_STATE; + +// STM Mapping +typedef struct { + uint64_t physical_address; + uint64_t virtual_ddress; + uint32_t Page_count; + uint32_t Pat_cache_type; +} STM_MAP_ADDRESS_RANGE_DESCRIPTOR; + +#define ST_UC 0x00 +#define WC 0x01 +#define WT 0x04 +#define WP 0x05 +#define WB 0x06 +#define UC 0x07 +#define FOLLOW_MTRR 0xFFFFFFFF + +typedef struct { + uint64_t virtual_address; + uint32_t length; +} STM_UNMAP_ADDRESS_RANGE_DESCRIPTOR; + +typedef struct { + uint64_t interrupted_guest_virtual_address; + uint32_t length; + uint64_t interrupted_cr3; + uint64_t interrupted_eptp; + uint32_t map_to_smm_guest : 2; + uint32_t interrupted_cr4_pae : 1; + uint32_t interrupted_cr4_pse : 1; + uint32_t interrupted_ia32e_mode : 1; + uint32_t reserved1 : 27; + uint32_t reserved2; + uint64_t physical_address; + uint64_t smm_guest_virtual_address; +} STM_ADDRESS_LOOKUP_DESCRIPTOR; + +#define DO_NOT_MAP 0 +#define ONE_TO_ONE 1 +#define VIRTUAL_ADDRESS_SPECIFIED 3 + +// STM_RESOURCE_LIST +#define END_OF_RESOURCES 0 +#define MEM_RANGE 1 +#define IO_RANGE 2 +#define MMIO_RANGE 3 +#define MACHINE_SPECIFIC_REG 4 +#define PCI_CFG_RANGE 5 +#define TRAPPED_IO_RANGE 6 +#define ALL_RESOURCES 7 +#define REGISTER_VIOLATION 8 +#define MAX_DESC_TYPE 8 + +typedef struct { + uint32_t rsc_type; + uint16_t length; + uint16_t return_status : 1; + uint16_t reserved : 14; + uint16_t ignore_resource : 1; +} STM_RSC_DESC_HEADER; + +typedef struct { + STM_RSC_DESC_HEADER Hdr; + uint64_t resource_list_continuation; +} STM_RSC_END; + +// byte granular Memory range support +#define STM_RSC_BGM 0x4 + +typedef struct { + STM_RSC_DESC_HEADER hdr; + uint64_t base; + uint64_t length; + uint32_t rwx_attributes : 3; + uint32_t reserved : 29; + uint32_t reserved_2; +} STM_RSC_MEM_DESC; + +#define STM_RSC_MEM_R 0x1 +#define STM_RSC_MEM_W 0x2 +#define STM_RSC_MEM_X 0x4 + +typedef struct { + STM_RSC_DESC_HEADER hdr; + uint16_t base; + uint16_t length; + uint32_t reserved; +} STM_RSC_IO_DESC; + +// byte granular MMIO range support +#define STM_RSC_BGI 0x2 + +typedef struct { + STM_RSC_DESC_HEADER hdr; + uint64_t base; + uint64_t length; + uint32_t rwx_attributes : 3; + uint32_t reserved : 29; + uint32_t reserved_2; +} STM_RSC_MMIO_DESC; + +#define STM_RSC_MMIO_R 0x1 +#define STM_RSC_MMIO_W 0x2 +#define STM_RSC_MMIO_X 0x4 + +typedef struct { + STM_RSC_DESC_HEADER hdr; + uint32_t msr_index; + uint32_t kernel_mode_processing : 1; + uint32_t reserved : 31; + uint64_t read_mask; + uint64_t write_mask; +} STM_RSC_MSR_DESC; + +// bit granular MSR resource support +#define STM_RSC_MSR 0x8 + +typedef struct { + uint8_t type; // must be 1, indicating Hardware Device Path + uint8_t subtype; // must be 1, indicating PCI + uint16_t length; // sizeof(STM_PCI_DEVICE_PATH_NODE) which is 6 + uint8_t pci_function; + uint8_t pci_device; +} STM_PCI_DEVICE_PATH_NODE; + +typedef struct { + STM_RSC_DESC_HEADER hdr; + uint16_t rw_attributes : 2; + uint16_t reserved : 14; + uint16_t base; + uint16_t length; + uint8_t originating_bus_number; + uint8_t last_node_index; + STM_PCI_DEVICE_PATH_NODE pci_device_path[1]; + // STM_PCI_DEVICE_PATH_NODE PciDevicePath[LastNodeIndex + 1]; +} STM_RSC_PCI_CFG_DESC; + +#define STM_RSC_PCI_CFG_R 0x1 +#define STM_RSC_PCI_CFG_W 0x2 + +typedef struct { + STM_RSC_DESC_HEADER hdr; + uint16_t base; + uint16_t length; + uint16_t in : 1; + uint16_t out : 1; + uint16_t api : 1; + uint16_t reserved1 : 13; + uint16_t reserved2; +} STM_RSC_TRAPPED_IO_DESC; + +typedef struct { + STM_RSC_DESC_HEADER hdr; +} STM_RSC_ALL_RESOURCES_DESC; + +typedef struct { + STM_RSC_DESC_HEADER hdr; + uint32_t register_type; + uint32_t reserved; + uint64_t readMask; + uint64_t write_mask; +} STM_REGISTER_VIOLATION_DESC; + +typedef enum { + stm_register_cr0, + stm_register_cr2, + stm_register_cr3, + stm_register_cr4, + stm_register_cr8, + stm_register_max, +} STM_REGISTER_VIOLATION_TYPE; + +typedef union { + STM_RSC_DESC_HEADER header; + STM_RSC_END end; + STM_RSC_MEM_DESC mem; + STM_RSC_IO_DESC io; + STM_RSC_MMIO_DESC mmio; + STM_RSC_MSR_DESC msr; + STM_RSC_PCI_CFG_DESC pci_cfg; + STM_RSC_TRAPPED_IO_DESC trapped_io; + STM_RSC_ALL_RESOURCES_DESC all; + STM_REGISTER_VIOLATION_DESC register_violation; +} STM_RSC; + +// VMCS database +#define STM_VMCS_DATABASE_REQUEST_ADD 1 +#define STM_VMCS_DATABASE_REQUEST_REMOVE 0 + +// Values for DomainType +// Interpreter of DomainType +#define DOMAIN_DISALLOWED_IO_OUT (1u << 0) +#define DOMAIN_DISALLOWED_IO_IN (1u << 1) +#define DOMAIN_INTEGRITY (1u << 2) +#define DOMAIN_CONFIDENTIALITY (1u << 3) + +#define DOMAIN_UNPROTECTED 0x00 +#define DOMAIN_INTEGRITY_PROT_OUT_IN (DOMAIN_INTEGRITY) +#define DOMAIN_FULLY_PROT_OUT_IN (DOMAIN_CONFIDENTIALITY | DOMAIN_INTEGRITY) +#define DOMAIN_FULLY_PROT \ + (DOMAIN_CONFIDENTIALITY | DOMAIN_INTEGRITY | DOMAIN_DISALLOWED_IO_IN \ + | DOMAIN_DISALLOWED_IO_OUT) + +// Values for XStatePolicy +#define XSTATE_READWRITE 0x00 +#define XSTATE_READONLY 0x01 +#define XSTATE_SCRUB 0x03 + +typedef struct { + uint64_t vmcs_phys_pointer; // bits 11:0 are reserved and must be 0 + uint32_t domain_type : 4; + uint32_t x_state_policy : 2; + uint32_t degradation_policy : 4; + uint32_t reserved1 : 22; // Must be 0 + uint32_t add_or_remove; +} STM_VMCS_DATABASE_REQUEST; + +// Event log +#define NEW_LOG 1 +#define CONFIGURE_LOG 2 +#define START_LOG 3 +#define STOP_LOG 4 +#define CLEAR_LOG 5 +#define DELETE_LOG 6 +typedef enum { + evt_log_started, + evt_log_stopped, + evt_log_invalid_parameter_detected, + evt_handled_protection_exception, + // unhandled protection exceptions result in reset & cannot be logged + evt_bios_access_to_unclaimed_resource, + evt_mle_resource_protection_granted, + evt_mle_resource_protection_denied, + evt_mle_resource_unprotect, + evt_mle_resource_unprotect_error, + evt_mle_domain_type_degraded, + // add more here + evt_mle_max, + // Not used + evt_invalid = 0xFFFFFFFF, +} EVENT_TYPE; + +typedef struct { + uint32_t page_count; + uint64_t pages[1]; // number of elements is PageCount +} STM_EVENT_LOG_MANAGEMENT_REQUEST_DATA_LOG_BUFFER; + +typedef union { + STM_EVENT_LOG_MANAGEMENT_REQUEST_DATA_LOG_BUFFER log_buffer; + uint32_t event_enable_bitmap; // bitmap of EVENT_TYPE +} STM_EVENT_LOG_MANAGEMENT_REQUEST_DATA; + +typedef struct { + uint32_t sub_functionindex; + STM_EVENT_LOG_MANAGEMENT_REQUEST_DATA data; +} STM_EVENT_LOG_MANAGEMENT_REQUEST; + +// VMCALL API Numbers +// +// API number convention: BIOS facing VMCALL interfaces have bit 16 clear +#define STM_API_MAP_ADDRESS_RANGE 0x00000001 +#define STM_API_UNMAP_ADDRESS_RANGE 0x00000002 +#define STM_API_ADDRESS_LOOKUP 0x00000003 +#define STM_API_RETURN_FROM_PROTECTION_EXCEPTION 0x00000004 + +// API number convention: MLE facing VMCALL interfaces have bit 16 set +// +// The STM configuration lifecycle is as follows: +// 1. SENTER->SINIT->MLE: MLE begins execution with SMI disabled (masked). +// 2. MLE invokes InitializeProtectionVMCALL() to prepare STM for setup of +// initial protection profile. This is done on a single CPU and has global +// effect. +// 3. MLE invokes ProtectResourceVMCALL() to define the initial protection +// profile. The protection profile is global across all CPUs. +// 4. MLE invokes StartStmVMCALL() to enable the STM to begin receiving SMI +// events. This must be done on every logical CPU. +// 5. MLE may invoke ProtectResourceVMCALL() or UnProtectResourceVMCALL() +// during runtime as many times as necessary. +// 6. MLE invokes StopStmVMCALL() to disable the STM. SMI is again masked +// following StopStmVMCALL(). +// +#define STM_API_START 0x00010001 +#define STM_API_STOP 0x00010002 +#define STM_API_PROTECT_RESOURCE 0x00010003 +#define STM_API_UNPROTECT_RESOURCE 0x00010004 +#define STM_API_GET_BIOS_RESOURCES 0x00010005 +#define STM_API_MANAGE_VMCS_DATABASE 0x00010006 +#define STM_API_INITIALIZE_PROTECTION 0x00010007 +#define STM_API_MANAGE_EVENT_LOG 0x00010008 + +// Return codes +typedef uint32_t STM_STATUS; + +#define STM_SUCCESS 0x00000000 +#define SMM_SUCCESS 0x00000000 +// all error codes have bit 31 set +// STM errors have bit 16 set +#define ERROR_STM_SECURITY_VIOLATION 0x80010001 +#define ERROR_STM_CACHE_TYPE_NOT_SUPPORTED 0x80010002 +#define ERROR_STM_PAGE_NOT_FOUND 0x80010003 +#define ERROR_STM_BAD_CR3 0x80010004 +#define ERROR_STM_PHYSICAL_OVER_4G 0x80010005 +#define ERROR_STM_VIRTUAL_SPACE_TOO_SMALL 0x80010006 +#define ERROR_STM_UNPROTECTABLE_RESOURCE 0x80010007 +#define ERROR_STM_ALREADY_STARTED 0x80010008 +#define ERROR_STM_WITHOUT_SMX_UNSUPPORTED 0x80010009 +#define ERROR_STM_STOPPED 0x8001000A +#define ERROR_STM_BUFFER_TOO_SMALL 0x8001000B +#define ERROR_STM_INVALID_VMCS_DATABASE 0x8001000C +#define ERROR_STM_MALFORMED_RESOURCE_LIST 0x8001000D +#define ERROR_STM_INVALID_PAGECOUNT 0x8001000E +#define ERROR_STM_LOG_ALLOCATED 0x8001000F +#define ERROR_STM_LOG_NOT_ALLOCATED 0x80010010 +#define ERROR_STM_LOG_NOT_STOPPED 0x80010011 +#define ERROR_STM_LOG_NOT_STARTED 0x80010012 +#define ERROR_STM_RESERVED_BIT_SET 0x80010013 +#define ERROR_STM_NO_EVENTS_ENABLED 0x80010014 +#define ERROR_STM_OUT_OF_RESOURCES 0x80010015 +#define ERROR_STM_FUNCTION_NOT_SUPPORTED 0x80010016 +#define ERROR_STM_UNPROTECTABLE 0x80010017 +#define ERROR_STM_UNSUPPORTED_MSR_BIT 0x80010018 +#define ERROR_STM_UNSPECIFIED 0x8001FFFF + +// SMM errors have bit 17 set +#define ERROR_SMM_BAD_BUFFER 0x80020001 +#define ERROR_SMM_INVALID_RSC 0x80020004 +#define ERROR_SMM_INVALID_BUFFER_SIZE 0x80020005 +#define ERROR_SMM_BUFFER_TOO_SHORT 0x80020006 +#define ERROR_SMM_INVALID_LIST 0x80020007 +#define ERROR_SMM_OUT_OF_MEMORY 0x80020008 +#define ERROR_SMM_AFTER_INIT 0x80020009 +#define ERROR_SMM_UNSPECIFIED 0x8002FFFF + +// Errors that apply to both have bits 15, 16, and 17 set +#define ERROR_INVALID_API 0x80038001 +#define ERROR_INVALID_PARAMETER 0x80038002 + +// STM TXT.ERRORCODE codes +#define STM_CRASH_PROTECTION_EXCEPTION 0xC000F001 +#define STM_CRASH_PROTECTION_EXCEPTION_FAILURE 0xC000F002 +#define STM_CRASH_DOMAIN_DEGRADATION_FAILURE 0xC000F003 +#define STM_CRASH_BIOS_PANIC 0xC000E000 + +typedef struct { + uint32_t event_serial_number; + uint16_t type; + uint16_t lock : 1; + uint16_t valid : 1; + uint16_t read_by_mle : 1; + uint16_t wrapped : 1; + uint16_t reserved : 12; +} LOG_ENTRY_HEADER; + +typedef struct { + uint32_t reserved; +} ENTRY_EVT_LOG_STARTED; + +typedef struct { + uint32_t reserved; +} ENTRY_EVT_LOG_STOPPED; + +typedef struct { + uint32_t vmcall_api_number; +} ENTRY_EVT_LOG_INVALID_PARAM; + +typedef struct { + STM_RSC resource; +} ENTRY_EVT_LOG_HANDLED_PROTECTION_EXCEPTION; + +typedef struct { + STM_RSC resource; +} ENTRY_EVT_BIOS_ACCESS_UNCLAIMED_RSC; + +typedef struct { + STM_RSC resource; +} ENTRY_EVT_MLE_RSC_PROT_GRANTED; + +typedef struct { + STM_RSC resource; +} ENTRY_EVT_MLE_RSC_PROT_DENIED; + +typedef struct { + STM_RSC resource; +} ENTRY_EVT_MLE_RSC_UNPROT; + +typedef struct { + STM_RSC resource; +} ENTRY_EVT_MLE_RSC_UNPROT_ERROR; + +typedef struct { + uint64_t vmcs_phys_pointer; + uint8_t expected_domain_type; + uint8_t degraded_domain_type; +} ENTRY_EVT_MLE_DOMAIN_TYPE_DEGRADED; + +typedef union { + ENTRY_EVT_LOG_STARTED started; + ENTRY_EVT_LOG_STOPPED stopped; + ENTRY_EVT_LOG_INVALID_PARAM invalid_param; + ENTRY_EVT_LOG_HANDLED_PROTECTION_EXCEPTION + handled_protection_exception; + ENTRY_EVT_BIOS_ACCESS_UNCLAIMED_RSC bios_unclaimed_rsc; + ENTRY_EVT_MLE_RSC_PROT_GRANTED mle_rsc_prot_granted; + ENTRY_EVT_MLE_RSC_PROT_DENIED mle_rsc_prot_denied; + ENTRY_EVT_MLE_RSC_UNPROT mle_rsc_unprot; + ENTRY_EVT_MLE_RSC_UNPROT_ERROR mle_rsc_unprot_error; + ENTRY_EVT_MLE_DOMAIN_TYPE_DEGRADED mle_domain_type_degraded; +} LOG_ENTRY_DATA; + +typedef struct { + LOG_ENTRY_HEADER hdr; + LOG_ENTRY_DATA data; +} STM_LOG_ENTRY; + +#define STM_LOG_ENTRY_SIZE 256 +#define STM_CONFIG_SMI_UNBLOCKING_BY_VMX_OFF 0x1 + +// TXT debug +#define SW_SMI_STM_ADD_RUNTIME_RESOURCES_SUB_FUNC 0 +#define SW_SMI_STM_READ_BIOS_RESOURCES_SUB_FUNC 1 +#define SW_SMI_STM_REPLACE_BIOS_RESOURCES_SUB_FUNC 2 + +typedef struct { + uint32_t buffer_size; + uint32_t reserved; + // uint8_t Data[]; +} TXT_BIOS_DEBUG; + +#pragma pack(pop) + +#endif diff --git a/src/security/intel/stm/StmPlatformResource.c b/src/security/intel/stm/StmPlatformResource.c new file mode 100644 index 0000000000..6fef515052 --- /dev/null +++ b/src/security/intel/stm/StmPlatformResource.c @@ -0,0 +1,188 @@ +/* @file + * STM platform SMM resource + * + * Copyright (c) 2015, Intel Corporation. All rights reserved. + * This program and the accompanying materials are licensed and made + * available under the terms and conditions of the BSD License which + * accompanies this distribution. The full text of the license may be found + * at http://opensource.org/licenses/bsd-license.php. + * + * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR + * IMPLIED. + */ + +#include +#include +#include +#include + +#if CONFIG(SOUTHBRIDGE_INTEL_COMMON_PMCLIB) +#include +#else +#include +#endif +#include +#include + +#define RDWR_ACCS 3 +#define FULL_ACCS 7 + +// Fixed memory ranges +// +// TSEG memory! +static STM_RSC_MEM_DESC rsc_tseg_memory = {{MEM_RANGE, sizeof(STM_RSC_MEM_DESC)}, + 0, + 0, + FULL_ACCS}; + +// Flash part +static STM_RSC_MEM_DESC rsc_spi_memory = { + {MEM_RANGE, sizeof(STM_RSC_MEM_DESC)}, + 0xFE000000, + 0x01000000, + FULL_ACCS}; + +// ACPI +static STM_RSC_IO_DESC rsc_pm_io = {{IO_RANGE, sizeof(STM_RSC_IO_DESC)}, 0, 128}; + +// PCIE MMIO +static STM_RSC_MMIO_DESC rsc_pcie_mmio = {{MMIO_RANGE, sizeof(STM_RSC_MMIO_DESC)}, + 0, + 0, // Length + RDWR_ACCS}; + +// Local APIC +static STM_RSC_MMIO_DESC rsc_apic_mmio = {{MMIO_RANGE, sizeof(STM_RSC_MMIO_DESC)}, + 0, + 0x400, + RDWR_ACCS}; + +// Software SMI +static STM_RSC_TRAPPED_IO_DESC rsc_sw_smi_trap_io = { + {TRAPPED_IO_RANGE, sizeof(STM_RSC_TRAPPED_IO_DESC)}, + 0xB2, + 2}; + +// End of list +static STM_RSC_END rsc_list_end __attribute__((used)) = { + {END_OF_RESOURCES, sizeof(STM_RSC_END)}, 0}; + +// Common PCI devices +// +// LPC bridge +STM_RSC_PCI_CFG_DESC rsc_lpc_bridge_pci = { + {PCI_CFG_RANGE, sizeof(STM_RSC_PCI_CFG_DESC)}, + RDWR_ACCS, + 0, + 0, + 0x1000, + 0, + 0, + { + {1, 1, sizeof(STM_PCI_DEVICE_PATH_NODE), LPC_FUNCTION, + LPC_DEVICE}, + }, +}; + +// Template for MSR resources. +STM_RSC_MSR_DESC rsc_msr_tpl = { + {MACHINE_SPECIFIC_REG, sizeof(STM_RSC_MSR_DESC)}, +}; + +// MSR indices to register +typedef struct { + uint32_t msr_index; + uint64_t read_mask; + uint64_t write_mask; +} MSR_TABLE_ENTRY; + +MSR_TABLE_ENTRY msr_table[] = { + // Index Read Write + // MASK64 means need access, MASK0 means no need access. + {SMRR_PHYSBASE_MSR, MASK64, MASK0}, + {SMRR_PHYSMASK_MSR, MASK64, MASK0}, +}; + +/* + * Fix up PCIE resource. + */ +static void fixup_pciex_resource(void) +{ + // Find max bus number and PCIEX length + rsc_pcie_mmio.length = CONFIG_SA_PCIEX_LENGTH; // 0x10000000;// 256 MB + rsc_pcie_mmio.base = CONFIG_MMCONF_BASE_ADDRESS; +} + +/* + * Add basic resources to BIOS resource database. + */ +static void add_simple_resources(void) +{ + int Status = 0; + msr_t ReadMsr; + + ReadMsr = rdmsr(SMRR_PHYSBASE_MSR); + rsc_tseg_memory.base = ReadMsr.lo & 0xFFFFF000; + + ReadMsr = rdmsr(SMRR_PHYSMASK_MSR); + rsc_tseg_memory.length = (~(ReadMsr.lo & 0xFFFFF000) + 1); + + rsc_pm_io.base = (uint16_t)get_pmbase(); + + // Local APIC. We assume that all thteads are programmed identically + // despite that it is possible to have individual APIC address for + // each of the threads. If this is the case this programming should + // be corrected. + ReadMsr = rdmsr(IA32_APIC_BASE_MSR_INDEX); + rsc_apic_mmio.base = ((uint64_t)ReadMsr.lo & 0xFFFFF000) | + ((uint64_t)(ReadMsr.hi & 0x0000000F) << 32); + + // PCIEX BAR + fixup_pciex_resource(); + + Status |= add_pi_resource((void *)&rsc_tseg_memory, 1); + Status |= add_pi_resource((void *)&rsc_spi_memory, 1); + + Status |= add_pi_resource((void *)&rsc_pm_io, 1); + Status |= add_pi_resource((void *)&rsc_pcie_mmio, 1); + Status |= add_pi_resource((void *)&rsc_apic_mmio, 1); + Status |= add_pi_resource((void *)&rsc_sw_smi_trap_io, 1); + + Status |= add_pi_resource((void *)&rsc_lpc_bridge_pci, 1); + + if (Status != 0) + printk(BIOS_DEBUG, "STM - Error in adding simple resources\n"); +} + +/* + * Add MSR resources to BIOS resource database. + */ +static void add_msr_resources(void) +{ + uint32_t Status = 0; + uint32_t Index; + + for (Index = 0; Index < ARRAY_SIZE(msr_table); Index++) { + + rsc_msr_tpl.msr_index = (uint32_t)msr_table[Index].msr_index; + rsc_msr_tpl.read_mask = (uint64_t)msr_table[Index].read_mask; + rsc_msr_tpl.write_mask = (uint64_t)msr_table[Index].write_mask; + + Status |= add_pi_resource((void *)&rsc_msr_tpl, 1); + } + + if (Status != 0) + printk(BIOS_DEBUG, "STM - Error in adding MSR resources\n"); +} + +/* + * Add resources to BIOS resource database. + */ +void add_resources_cmd(void) +{ + + add_simple_resources(); + + add_msr_resources(); +} diff --git a/src/security/intel/stm/StmPlatformResource.h b/src/security/intel/stm/StmPlatformResource.h new file mode 100644 index 0000000000..7db2fc0330 --- /dev/null +++ b/src/security/intel/stm/StmPlatformResource.h @@ -0,0 +1,32 @@ +/* @file + * STM platform SMM resource + * + * Copyright (c) 2015, Intel Corporation. All rights reserved. + * This program and the accompanying materials are licensed and made available + * under the terms and conditions of the BSD License which accompanies this + * distribution. The full text of the license may be found at + * http://opensource.org/licenses/bsd-license.php. + * + * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR + * IMPLIED. + */ + +#ifndef _STM_PLATFORM_RESOURCE_H_ +#define _STM_PLATFORM_RESOURCE_H_ + +#define MASK0 0 +#define MASK64 0xFFFFFFFFFFFFFFFFull + +// LPC + +#define LPC_DEVICE 31 +#define LPC_FUNCTION 0 +#define R_ACPI_PM_BASE 0x40 +#define ACPI_PM_BASE_MASK 0xFFF8 + +/* + * Add resources to BIOS resource database. + */ +void add_resources_cmd(void); +#endif diff --git a/src/security/intel/stm/StmPlatformSmm.c b/src/security/intel/stm/StmPlatformSmm.c new file mode 100644 index 0000000000..d7064b07f5 --- /dev/null +++ b/src/security/intel/stm/StmPlatformSmm.c @@ -0,0 +1,204 @@ +/* @file + * STM platform SMM API + * + * Copyright (c) 2015, Intel Corporation. All rights reserved. + * This program and the accompanying materials are licensed and made + * available under the terms and conditions of the BSD License which + * accompanies this distribution. The full text of the license may be found + * at http://opensource.org/licenses/bsd-license.php. + * + * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR + * IMPLIED. + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* + * Load STM image to MSEG + * + * @retval SUCCESS STM is loaded to MSEG + */ +int load_stm_image(uintptr_t mseg) +{ + int status; + void *mseg_base; + uint32_t stm_buffer_size; + uint32_t stm_image_size; + bool stm_status; + + STM_HEADER *stm_header; + + // Extract STM image from FV + mseg_base = (void *)mseg; + stm_buffer_size = CONFIG_MSEG_SIZE; + stm_image_size = 0; + + memset((void *)mseg_base, 0, CONFIG_MSEG_SIZE); // clear the mseg + + stm_image_size = cbfs_boot_load_file("stm.bin", mseg_base, + stm_buffer_size, CBFS_TYPE_RAW); + printk(BIOS_DEBUG, "STM:loaded into mseg: 0x%p size: %u\n", mseg_base, + stm_image_size); + /* status is number of bytes loaded */ + stm_status = stm_check_stm_image(mseg_base, stm_image_size); + + if (!stm_status) { + printk(BIOS_DEBUG, "STM: Error in STM image\n"); + return -1; + } + + stm_header = mseg_base; + + stm_gen_4g_pagetable_x64((uint32_t)mseg_base + + stm_header->hw_stm_hdr.cr3_offset); + + // Debug stuff + printk(BIOS_DEBUG, + "STM: Header-Revision %d Features 0x%08x Cr3Offset 0x%08x\n", + stm_header->hw_stm_hdr.stm_header_revision, + stm_header->hw_stm_hdr.monitor_features, + stm_header->hw_stm_hdr.cr3_offset); + printk(BIOS_DEBUG, + "STM: Header-StaticImageSize: %d Cr3Location: 0x%08x\n", + stm_header->sw_stm_hdr.static_image_size, + ((uint32_t)mseg_base + stm_header->hw_stm_hdr.cr3_offset)); + + status = 0; // always return good for now + + return status; +} + +struct descriptor { + uint16_t limit; + uintptr_t base; +} __attribute__((packed)); + + +static void read_gdtr(struct descriptor *gdtr) +{ + __asm__ __volatile__("sgdt %0" : "=m"(*gdtr)); +} + +void setup_smm_descriptor(void *smbase, void *base_smbase, int32_t apic_id, + int32_t entry32_off) +{ + struct descriptor gdtr; + void *smbase_processor; + //msr_t smbase_msr; + + TXT_PROCESSOR_SMM_DESCRIPTOR *psd; + + smbase_processor = (void *) SMM_DEFAULT_BASE;//we are here + psd = smbase + SMM_PSD_OFFSET; + + printk(BIOS_DEBUG, + "STM: Smm Descriptor setup: Smbase: %p Smbase_processor: %p Psd: %p\n", + smbase, + smbase_processor, + psd); + + memset(psd, 0, sizeof(TXT_PROCESSOR_SMM_DESCRIPTOR)); + + memcpy(&psd->signature, TXT_PROCESSOR_SMM_DESCRIPTOR_SIGNATURE, 8); + psd->smm_descriptor_ver_major = + TXT_PROCESSOR_SMM_DESCRIPTOR_VERSION_MAJOR; + psd->smm_descriptor_ver_minor = + TXT_PROCESSOR_SMM_DESCRIPTOR_VERSION_MINOR; + psd->smm_smi_handler_rip = + (uint64_t)((uintptr_t)base_smbase + SMM_ENTRY_OFFSET + + entry32_off); + psd->local_apic_id = apic_id; + psd->size = sizeof(TXT_PROCESSOR_SMM_DESCRIPTOR); + psd->acpi_rsdp = 0; + psd->bios_hw_resource_requirements_ptr = + (uint64_t)((uintptr_t)get_stm_resource()); + psd->smm_cs = ROM_CODE_SEG; + psd->smm_ds = ROM_DATA_SEG; + psd->smm_ss = ROM_DATA_SEG; + psd->smm_other_segment = ROM_DATA_SEG; + psd->smm_tr = SMM_TASK_STATE_SEG; + + + // At this point the coreboot smm_stub is relative to the default + // smbase and not the one for the smi handler in tseg. So we have + // to adjust the gdtr.base + + read_gdtr(&gdtr); + + gdtr.base -= (uintptr_t) smbase_processor; + gdtr.base += (uintptr_t) base_smbase; + + psd->smm_gdt_ptr = gdtr.base; + psd->smm_gdt_size = gdtr.limit + 1; // the stm will subtract, so add + printk(BIOS_DEBUG, "STM: Smm Descriptor setup complete - Smbase: %p Psd: %p\n", + smbase, psd); +} + +extern uint8_t *stm_resource_heap; + +#define FXSAVE_SIZE 512 + +static int stm_load_status = 0; + +void stm_setup(uintptr_t mseg, int cpu, int num_cpus, uintptr_t smbase, + uintptr_t base_smbase, uint32_t offset32) +{ + msr_t InitMseg; + msr_t MsegChk; + uintptr_t addr_calc; // used to calculate the stm resource heap area + + printk(BIOS_DEBUG, "STM: set up for cpu %d/%d\n", cpu, num_cpus); + if (cpu == 0) { + + // need to create the BIOS resource list once + // first calculate the location in SMRAM + addr_calc = (mseg - (CONFIG_SMM_MODULE_STACK_SIZE * num_cpus)); + + if (CONFIG(SSE)) + addr_calc -= FXSAVE_SIZE * num_cpus; + + addr_calc -= CONFIG_BIOS_RESOURCE_LIST_SIZE; + stm_resource_heap = (uint8_t *) addr_calc; + printk(BIOS_DEBUG, "STM: stm_resource_heap located at %p\n", + stm_resource_heap); + //setup the the list + add_resources_cmd(); + + stm_load_status = load_stm_image(mseg); + } + + if (stm_load_status == 0) { + // enable STM for this cpu + InitMseg.lo = mseg | IA32_SMM_MONITOR_VALID; + InitMseg.hi = 0; + + wrmsr(IA32_SMM_MONITOR_CTL_MSR, InitMseg); + + MsegChk = rdmsr(IA32_SMM_MONITOR_CTL_MSR); + + printk(BIOS_DEBUG, "STM: MSEG Initialized (%d) 0x%08x 0x%08x\n", + cpu, MsegChk.hi, MsegChk.lo); + + // setup the descriptor for this cpu + setup_smm_descriptor((void *)smbase, (void *) base_smbase, + cpu, offset32); + } else { + printk(BIOS_DEBUG, + "STM: Error in STM load, STM not enabled: %d\n", + cpu); + } +} From c7af5ef509aee3c39b3cb3cbf01e4928963b139a Mon Sep 17 00:00:00 2001 From: Eugene Myers Date: Wed, 12 Feb 2020 13:31:30 -0500 Subject: [PATCH 29/67] security/intel/stm: Check for processor STM support Check to ensure that dual monitor mode is supported on the current processor. Dual monitor mode is normally supported on any Intel x86 processor that has VTx support. The STM is a hypervisor that executes in SMM dual monitor mode. This check should fail only in the rare case were dual monitor mode is disabled. If the check fails, then the STM will not be initialized by coreboot. Original-Signed-off-by: Eugene D. Myers Original-Change-Id: I518bb2aa1bdec94b5b6d5e991d7575257f3dc6e9 Original-Reviewed-on: https://review.coreboot.org/c/coreboot/+/38836 Original-Tested-by: build bot (Jenkins) Original-Reviewed-by: Nico Huber (cherry picked from commit 5544f62746aeb8e5e1a7916d9b509f4d9339f387) Signed-off-by: Marc Jones Change-Id: I312570ca28329490006283251f69dd83ef64af40 Reviewed-on: https://review.coreboot.org/c/coreboot/+/50309 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer Reviewed-by: Jay Talbott --- src/include/cpu/x86/msr.h | 1 + src/security/intel/stm/StmPlatformSmm.c | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/src/include/cpu/x86/msr.h b/src/include/cpu/x86/msr.h index ad07742d2f..b97caf44a5 100644 --- a/src/include/cpu/x86/msr.h +++ b/src/include/cpu/x86/msr.h @@ -74,6 +74,7 @@ #define MCA_STATUS_LO_ERRCODE_EXT_MASK (0x3f << MCA_STATUS_LO_ERRCODE_EXT_SH) #define MCA_STATUS_LO_ERRCODE_MASK (0xffff << 0) #define IA32_VMX_BASIC_MSR 0x480 +#define VMX_BASIC_HI_DUAL_MONITOR (1UL << (49 - 32)) #define IA32_VMX_MISC_MSR 0x485 #define MC0_ADDR 0x402 #define MC0_MISC 0x403 diff --git a/src/security/intel/stm/StmPlatformSmm.c b/src/security/intel/stm/StmPlatformSmm.c index d7064b07f5..45db0e069f 100644 --- a/src/security/intel/stm/StmPlatformSmm.c +++ b/src/security/intel/stm/StmPlatformSmm.c @@ -159,9 +159,20 @@ void stm_setup(uintptr_t mseg, int cpu, int num_cpus, uintptr_t smbase, { msr_t InitMseg; msr_t MsegChk; + msr_t vmx_basic; + uintptr_t addr_calc; // used to calculate the stm resource heap area printk(BIOS_DEBUG, "STM: set up for cpu %d/%d\n", cpu, num_cpus); + + vmx_basic = rdmsr(IA32_VMX_BASIC_MSR); + + // Does this processor support an STM? + if ((vmx_basic.hi & VMX_BASIC_HI_DUAL_MONITOR) != VMX_BASIC_HI_DUAL_MONITOR) { + printk(BIOS_WARNING, "STM: not supported on CPU %d\n", cpu); + return; + } + if (cpu == 0) { // need to create the BIOS resource list once From fc8a6fa93a30937414609266f3dddb80670b1589 Mon Sep 17 00:00:00 2001 From: Arthur Heymans Date: Wed, 27 Nov 2019 16:21:46 +0100 Subject: [PATCH 30/67] cpu/x86/smm: Add smm_size to relocatable smmstub To mitigate against sinkhole in software which is required on pre-sandybridge hardware, the smm entry point needs to check if the LAPIC base is between smbase and smbase + smmsize. The size needs to be available early so add them to the relocatable module parameters. When the smmstub is used to relocate SMM the default SMM size 0x10000 is provided. On the permanent handler the size provided by get_smm_info() is used. Original-Change-Id: I0df6e51bcba284350f1c849ef3d012860757544b Original-Signed-off-by: Arthur Heymans Original-Reviewed-on: https://review.coreboot.org/c/coreboot/+/37288 Original-Tested-by: build bot (Jenkins) Original-Reviewed-by: Patrick Georgi (cherry picked from commit a3eb3df01c9f1ed6fc0bd3ef341a01981d4e7479) Signed-off-by: Marc Jones Change-Id: I4948639a513b196382eb38616fe872b72bb7e59e Reviewed-on: https://review.coreboot.org/c/coreboot/+/50310 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer Reviewed-by: Jay Talbott --- src/cpu/x86/smm/smm_module_loader.c | 11 +++++++---- src/cpu/x86/smm/smm_stub.S | 2 ++ src/include/cpu/x86/smm.h | 1 + 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/cpu/x86/smm/smm_module_loader.c b/src/cpu/x86/smm/smm_module_loader.c index a421436893..0940e34002 100644 --- a/src/cpu/x86/smm/smm_module_loader.c +++ b/src/cpu/x86/smm/smm_module_loader.c @@ -174,8 +174,9 @@ static void smm_stub_place_staggered_entry_points(char *base, * concurrent areas requested. The save state always lives at the top of SMRAM * space, and the entry point is at offset 0x8000. */ -static int smm_module_setup_stub(void *smbase, struct smm_loader_params *params, - void *fxsave_area) +static int smm_module_setup_stub(void *smbase, size_t smm_size, + struct smm_loader_params *params, + void *fxsave_area) { size_t total_save_state_size; size_t smm_stub_size; @@ -267,6 +268,7 @@ static int smm_module_setup_stub(void *smbase, struct smm_loader_params *params, stub_params->fxsave_area = (uintptr_t)fxsave_area; stub_params->fxsave_area_size = FXSAVE_SIZE; stub_params->runtime.smbase = (uintptr_t)smbase; + stub_params->runtime.smm_size = smm_size; stub_params->runtime.save_state_size = params->per_cpu_save_state_size; stub_params->runtime.num_cpus = params->num_concurrent_stacks; @@ -307,7 +309,8 @@ int smm_setup_relocation_handler(struct smm_loader_params *params) if (params->num_concurrent_stacks == 0) params->num_concurrent_stacks = CONFIG_MAX_CPUS; - return smm_module_setup_stub(smram, params, fxsave_area_relocation); + return smm_module_setup_stub(smram, SMM_DEFAULT_SIZE, + params, fxsave_area_relocation); } /* The SMM module is placed within the provided region in the following @@ -408,5 +411,5 @@ int smm_load_module(void *smram, size_t size, struct smm_loader_params *params) params->handler = rmodule_entry(&smm_mod); params->handler_arg = rmodule_parameters(&smm_mod); - return smm_module_setup_stub(smram, params, fxsave_area); + return smm_module_setup_stub(smram, size, params, fxsave_area); } diff --git a/src/cpu/x86/smm/smm_stub.S b/src/cpu/x86/smm/smm_stub.S index 8207d233a0..aa4022389f 100644 --- a/src/cpu/x86/smm/smm_stub.S +++ b/src/cpu/x86/smm/smm_stub.S @@ -42,6 +42,8 @@ fxsave_area_size: smm_runtime: smbase: .long 0 +smm_size: +.long 0 save_state_size: .long 0 num_cpus: diff --git a/src/include/cpu/x86/smm.h b/src/include/cpu/x86/smm.h index 9efe2e04eb..26496eebac 100644 --- a/src/include/cpu/x86/smm.h +++ b/src/include/cpu/x86/smm.h @@ -63,6 +63,7 @@ extern unsigned char _binary_smm_end[]; struct smm_runtime { u32 smbase; + u32 smm_size; u32 save_state_size; u32 num_cpus; /* STM's 32bit entry into SMI handler */ From b450c8d2cbd072859340a3cda81407ad4dccd16d Mon Sep 17 00:00:00 2001 From: Nico Huber Date: Fri, 7 Feb 2020 17:11:40 +0100 Subject: [PATCH 31/67] cpu/x86/smm: Add overflow check Rather bail out than run into undefined behavior. Original-Change-Id: Ife26a0abed0ce6bcafe1e7cd8f499618631c4df4 Original-Signed-off-by: Nico Huber Original-Reviewed-on: https://review.coreboot.org/c/coreboot/+/38763 Original-Tested-by: build bot (Jenkins) Original-Reviewed-by: Patrick Rudolph Original-Reviewed-by: Angel Pons Original-Reviewed-by: (cherry picked from commit 6d5f007813f6a2ffbdd6a633f31d207672eee2e1) Signed-off-by: Marc Jones Change-Id: I28e10d8836ab80c6fec9d3414c795c5e6ff312e8 Reviewed-on: https://review.coreboot.org/c/coreboot/+/50311 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer Reviewed-by: Jay Talbott --- src/cpu/x86/smm/smm_module_loader.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/cpu/x86/smm/smm_module_loader.c b/src/cpu/x86/smm/smm_module_loader.c index 0940e34002..3ed20b70bd 100644 --- a/src/cpu/x86/smm/smm_module_loader.c +++ b/src/cpu/x86/smm/smm_module_loader.c @@ -203,6 +203,8 @@ static int smm_module_setup_stub(void *smbase, size_t smm_size, /* Adjust remaining size to account for save state. */ total_save_state_size = params->per_cpu_save_state_size * params->num_concurrent_save_states; + if (total_save_state_size > size) + return -1; size -= total_save_state_size; /* The save state size encroached over the first SMM entry point. */ From 6b395cb19077864571d1c85a55b076e8f4c5a2e8 Mon Sep 17 00:00:00 2001 From: Eugene D Myers Date: Wed, 15 Apr 2020 18:28:10 -0400 Subject: [PATCH 32/67] intel/stm: Place resource list right below MSEG Suggested by Nico Huber in CB:38765. This placement makes the address calculation simpler and makes its location indepedent of the number of CPUs. As part of the change in the BIOS resource list address calculation, the `size` variable was factored out of the conditional in line 361, thus eliminating the else. Original-Change-Id: I9ee2747474df02b0306530048bdec75e95413b5d Original-Signed-off-by: Eugene D Myers Original-Reviewed-on: https://review.coreboot.org/c/coreboot/+/40437 Original-Reviewed-by: Nico Huber Original-Reviewed-by: Angel Pons Original-Tested-by: build bot (Jenkins) (cherry picked from commit 076605bc92730553e9adae543713f0d356a94709) Signed-off-by: Marc Jones Change-Id: Ie62e2bdccd2d09084cc39a0f2fe32df236c08cd6 Reviewed-on: https://review.coreboot.org/c/coreboot/+/50312 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer Reviewed-by: Jay Talbott Reviewed-by: Eugene Myers Reviewed-by: Paul Menzel --- src/cpu/x86/smm/smm_module_loader.c | 19 +++++++------------ src/security/intel/stm/StmPlatformSmm.c | 7 +------ 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/src/cpu/x86/smm/smm_module_loader.c b/src/cpu/x86/smm/smm_module_loader.c index 3ed20b70bd..19acea60d6 100644 --- a/src/cpu/x86/smm/smm_module_loader.c +++ b/src/cpu/x86/smm/smm_module_loader.c @@ -318,13 +318,13 @@ int smm_setup_relocation_handler(struct smm_loader_params *params) /* The SMM module is placed within the provided region in the following * manner: * +-----------------+ <- smram + size - * | stacks | - * +-----------------+ <- smram + size - total_stack_size - * | fxsave area | - * +-----------------+ <- smram + size - total_stack_size - fxsave_size * | BIOS resource | * | list (STM) | - * +-----------------+ <- .. - CONFIG_BIOS_RESOURCE_LIST_SIZE + * +-----------------+ <- smram + size - CONFIG_BIOS_RESOURCE_LIST_SIZE + * | stacks | + * +-----------------+ <- .. - total_stack_size + * | fxsave area | + * +-----------------+ <- .. - total_stack_size - fxsave_size * | ... | * +-----------------+ <- smram + handler_size + SMM_DEFAULT_SIZE * | handler | @@ -365,11 +365,10 @@ int smm_load_module(void *smram, size_t size, struct smm_loader_params *params) /* Stacks start at the top of the region. */ base = smram; + base += size; if (CONFIG(STM)) - base += size - CONFIG_MSEG_SIZE; // take out the mseg - else - base += size; + base -= CONFIG_MSEG_SIZE + CONFIG_BIOS_RESOURCE_LIST_SIZE; params->stack_top = base; @@ -400,10 +399,6 @@ int smm_load_module(void *smram, size_t size, struct smm_loader_params *params) total_size = total_stack_size + handler_size; total_size += fxsave_size + SMM_DEFAULT_SIZE; - // account for the bios resource list - if (CONFIG(STM)) - total_size += CONFIG_BIOS_RESOURCE_LIST_SIZE; - if (total_size > size) return -1; diff --git a/src/security/intel/stm/StmPlatformSmm.c b/src/security/intel/stm/StmPlatformSmm.c index 45db0e069f..248ccc028a 100644 --- a/src/security/intel/stm/StmPlatformSmm.c +++ b/src/security/intel/stm/StmPlatformSmm.c @@ -177,12 +177,7 @@ void stm_setup(uintptr_t mseg, int cpu, int num_cpus, uintptr_t smbase, // need to create the BIOS resource list once // first calculate the location in SMRAM - addr_calc = (mseg - (CONFIG_SMM_MODULE_STACK_SIZE * num_cpus)); - - if (CONFIG(SSE)) - addr_calc -= FXSAVE_SIZE * num_cpus; - - addr_calc -= CONFIG_BIOS_RESOURCE_LIST_SIZE; + addr_calc = mseg - CONFIG_BIOS_RESOURCE_LIST_SIZE; stm_resource_heap = (uint8_t *) addr_calc; printk(BIOS_DEBUG, "STM: stm_resource_heap located at %p\n", stm_resource_heap); From 5434988bac2175c66fbe29b76d277abf2c0e1819 Mon Sep 17 00:00:00 2001 From: Rocky Phagura Date: Tue, 21 Jul 2020 14:48:48 -0700 Subject: [PATCH 33/67] cpu/x86/smm: Introduce SMM module loader version 2 Xeon-SP Skylake Scalable Processor can have 36 CPU threads (18 cores). Current coreboot SMM is unable to handle more than ~32 CPU threads. This patch introduces a version 2 of the SMM module loader which addresses this problem. Having two versions of the SMM module loader prevents any issues to current projects. Future Xeon-SP products will be using this version of the SMM loader. Subsequent patches will enable board specific functionality for Xeon-SP. The reason for moving to version 2 is the state save area begins to encroach upon the SMI handling code when more than 32 CPU threads are in the system. This can cause system hangs, reboots, etc. The second change is related to staggered entry points with simple near jumps. In the current loader, near jumps will not work because the CPU is jumping within the same code segment. In version 2, "far" address jumps are necessary therefore protected mode must be enabled first. The SMM layout and how the CPUs are staggered are documented in the code. By making the modifications above, this allows the smm module loader to expand easily as more CPU threads are added. TEST=build for Tiogapass platform under OCP mainboard. Enable the following in Kconfig. select CPU_INTEL_COMMON_SMM select SOC_INTEL_COMMON_BLOCK_SMM select SMM_TSEG select HAVE_SMI_HANDLER select ACPI_INTEL_HARDWARE_SLEEP_VALUES Debug console will show all 36 cores relocated. Further tested by generating SMI's to port 0xb2 using XDP/ITP HW debugger and ensured all cores entering and exiting SMM properly. In addition, booted to Linux 5.4 kernel and observed no issues during mp init. Original-Change-Id: I00a23a5f2a46110536c344254868390dbb71854c Original-Signed-off-by: Rocky Phagura Original-Reviewed-on: https://review.coreboot.org/c/coreboot/+/43684 Original-Tested-by: build bot (Jenkins) Original-Reviewed-by: Angel Pons (cherry picked from commit afb7a814783cda12f5b72167163b9109ee1d15a7) Signed-off-by: Marc Jones Change-Id: I76bb506de56c816f6c0635bfd990125b789c5877 Reviewed-on: https://review.coreboot.org/c/coreboot/+/50313 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer Reviewed-by: Jay Talbott Reviewed-by: Rocky Phagura --- src/cpu/x86/Kconfig | 8 + src/cpu/x86/mp_init.c | 39 +- src/cpu/x86/smm/Makefile.inc | 4 + src/cpu/x86/smm/smm_module_loaderv2.c | 666 ++++++++++++++++++++++++++ src/include/cpu/x86/smm.h | 18 + 5 files changed, 727 insertions(+), 8 deletions(-) create mode 100644 src/cpu/x86/smm/smm_module_loaderv2.c diff --git a/src/cpu/x86/Kconfig b/src/cpu/x86/Kconfig index 85ebd831ea..1c714d1656 100644 --- a/src/cpu/x86/Kconfig +++ b/src/cpu/x86/Kconfig @@ -137,6 +137,14 @@ config SMM_STUB_STACK_SIZE endif +config X86_SMM_LOADER_VERSION2 + bool + default n + depends on HAVE_SMI_HANDLER + help + This option enables SMM module loader that works with server + platforms which may contain more than 32 CPU threads. + config SMM_LAPIC_REMAP_MITIGATION bool default y if NORTHBRIDGE_INTEL_I945 diff --git a/src/cpu/x86/mp_init.c b/src/cpu/x86/mp_init.c index 32450c8212..57b88653c5 100644 --- a/src/cpu/x86/mp_init.c +++ b/src/cpu/x86/mp_init.c @@ -736,12 +736,21 @@ static void asmlinkage smm_do_relocation(void *arg) * the location of the new SMBASE. If using SMM modules then this * calculation needs to match that of the module loader. */ +#if CONFIG(X86_SMM_LOADER_VERSION2) + perm_smbase = smm_get_cpu_smbase(cpu); + mp_state.perm_smbase = perm_smbase; + if (!perm_smbase) { + printk(BIOS_ERR, "%s: bad SMBASE for CPU %d\n", __func__, cpu); + return; + } +#else perm_smbase = mp_state.perm_smbase; perm_smbase -= cpu * runtime->save_state_size; - - printk(BIOS_DEBUG, "New SMBASE 0x%08lx\n", perm_smbase); +#endif /* Setup code checks this callback for validity. */ + printk(BIOS_INFO, "%s : curr_smbase 0x%x perm_smbase 0x%x, cpu = %d\n", + __func__, (int)curr_smbase, (int)perm_smbase, cpu); mp_state.ops.relocation_handler(cpu, curr_smbase, perm_smbase); if (CONFIG(STM)) { @@ -773,9 +782,17 @@ static void adjust_smm_apic_id_map(struct smm_loader_params *smm_params) static int install_relocation_handler(int num_cpus, size_t save_state_size) { + int cpus = num_cpus; +#if CONFIG(X86_SMM_LOADER_VERSION2) + /* Default SMRAM size is not big enough to concurrently + * handle relocation for more than ~32 CPU threads + * therefore, relocate 1 by 1. */ + cpus = 1; +#endif + struct smm_loader_params smm_params = { .per_cpu_stack_size = CONFIG_SMM_STUB_STACK_SIZE, - .num_concurrent_stacks = num_cpus, + .num_concurrent_stacks = cpus, .per_cpu_save_state_size = save_state_size, .num_concurrent_save_states = 1, .handler = smm_do_relocation, @@ -785,9 +802,10 @@ static int install_relocation_handler(int num_cpus, size_t save_state_size) if (mp_state.ops.adjust_smm_params != NULL) mp_state.ops.adjust_smm_params(&smm_params, 0); - if (smm_setup_relocation_handler(&smm_params)) + if (smm_setup_relocation_handler(&smm_params)) { + printk(BIOS_ERR, "%s: smm setup failed\n", __func__); return -1; - + } adjust_smm_apic_id_map(&smm_params); return 0; @@ -796,8 +814,13 @@ static int install_relocation_handler(int num_cpus, size_t save_state_size) 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 1KiB. */ + /* + * All the CPUs will relocate to permanaent handler now. Set parameters + * needed for all CPUs. The placement of each CPUs entry point is + * determined by the loader. This code simply provides the beginning of + * SMRAM region, the number of CPUs who will use the handler, the stack + * size and save state size for each CPU. + */ struct smm_loader_params smm_params = { .per_cpu_stack_size = CONFIG_SMM_MODULE_STACK_SIZE, .num_concurrent_stacks = num_cpus, @@ -809,7 +832,7 @@ static int install_permanent_handler(int num_cpus, uintptr_t smbase, 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); + printk(BIOS_DEBUG, "Installing permanent SMM handler to 0x%08lx\n", smbase); if (smm_load_module((void *)smbase, smsize, &smm_params)) return -1; diff --git a/src/cpu/x86/smm/Makefile.inc b/src/cpu/x86/smm/Makefile.inc index 11a4e67199..3064194f72 100644 --- a/src/cpu/x86/smm/Makefile.inc +++ b/src/cpu/x86/smm/Makefile.inc @@ -11,7 +11,11 @@ ## GNU General Public License for more details. ## +ifeq ($(CONFIG_X86_SMM_LOADER_VERSION2),y) +ramstage-y += smm_module_loaderv2.c +else ramstage-y += smm_module_loader.c +endif ifeq ($(CONFIG_ARCH_RAMSTAGE_X86_32),y) $(eval $(call create_class_compiler,smm,x86_32)) diff --git a/src/cpu/x86/smm/smm_module_loaderv2.c b/src/cpu/x86/smm/smm_module_loaderv2.c new file mode 100644 index 0000000000..04654f77c9 --- /dev/null +++ b/src/cpu/x86/smm/smm_module_loaderv2.c @@ -0,0 +1,666 @@ +/* + * This file is part of the coreboot project. + * + * 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 +#include +#include +#include +#include +#include +#include + +#define FXSAVE_SIZE 512 +#define SMM_CODE_SEGMENT_SIZE 0x10000 +/* FXSAVE area during relocation. While it may not be strictly needed the + SMM stub code relies on the FXSAVE area being non-zero to enable SSE + instructions within SMM mode. */ +static uint8_t fxsave_area_relocation[CONFIG_MAX_CPUS][FXSAVE_SIZE] +__attribute__((aligned(16))); + +/* + * Components that make up the SMRAM: + * 1. Save state - the total save state memory used + * 2. Stack - stacks for the CPUs in the SMM handler + * 3. Stub - SMM stub code for calling into handler + * 4. Handler - C-based SMM handler. + * + * The components are assumed to consist of one consecutive region. + */ + +/* These parameters are used by the SMM stub code. A pointer to the params + * is also passed to the C-base handler. */ +struct smm_stub_params { + u32 stack_size; + u32 stack_top; + u32 c_handler; + u32 c_handler_arg; + u32 fxsave_area; + u32 fxsave_area_size; + struct smm_runtime runtime; +} __packed; + +/* + * The stub is the entry point that sets up protected mode and stacks for each + * CPU. It then calls into the SMM handler module. It is encoded as an rmodule. + */ +extern unsigned char _binary_smmstub_start[]; + +/* Per CPU minimum stack size. */ +#define SMM_MINIMUM_STACK_SIZE 32 + +struct cpu_smm_info { + uint8_t active; + uintptr_t smbase; + uintptr_t entry; + uintptr_t ss_start; + uintptr_t code_start; + uintptr_t code_end; +}; +struct cpu_smm_info cpus[CONFIG_MAX_CPUS] = { 0 }; + +/* + * This method creates a map of all the CPU entry points, save state locations + * and the beginning and end of code segments for each CPU. This map is used + * during relocation to properly align as many CPUs that can fit into the SMRAM + * region. For more information on how SMRAM works, refer to the latest Intel + * developer's manuals (volume 3, chapter 34). SMRAM is divided up into the + * following regions: + * +-----------------+ Top of SMRAM + * | | <- MSEG, FXSAVE + * +-----------------+ + * | common | + * | smi handler | 64K + * | | + * +-----------------+ + * | CPU 0 code seg | + * +-----------------+ + * | CPU 1 code seg | + * +-----------------+ + * | CPU x code seg | + * +-----------------+ + * | | + * | | + * +-----------------+ + * | stacks | + * +-----------------+ <- START of SMRAM + * + * The code below checks when a code segment is full and begins placing the remainder + * CPUs in the lower segments. The entry point for each CPU is smbase + 0x8000 + * and save state is smbase + 0x8000 + (0x8000 - state save size). Save state + * area grows downward into the CPUs entry point. Therefore staggering too many + * CPUs in one 32K block will corrupt CPU0's entry code as the save states move + * downward. + * input : smbase of first CPU (all other CPUs + * will go below this address) + * input : num_cpus in the system. The map will + * be created from 0 to num_cpus. + */ +static int smm_create_map(uintptr_t smbase, unsigned int num_cpus, + const struct smm_loader_params *params) +{ + unsigned int i; + struct rmodule smm_stub; + unsigned int ss_size = params->per_cpu_save_state_size, stub_size; + unsigned int smm_entry_offset = params->smm_main_entry_offset; + unsigned int seg_count = 0, segments = 0, available; + unsigned int cpus_in_segment = 0; + unsigned int base = smbase; + + if (rmodule_parse(&_binary_smmstub_start, &smm_stub)) { + printk(BIOS_ERR, "%s: unable to get SMM module size\n", __func__); + return 0; + } + + stub_size = rmodule_memory_size(&smm_stub); + /* How many CPUs can fit into one 64K segment? */ + available = 0xFFFF - smm_entry_offset - ss_size - stub_size; + if (available > 0) { + cpus_in_segment = available / ss_size; + /* minimum segments needed will always be 1 */ + segments = num_cpus / cpus_in_segment + 1; + printk(BIOS_DEBUG, + "%s: cpus allowed in one segment %d\n", __func__, cpus_in_segment); + printk(BIOS_DEBUG, + "%s: min # of segments needed %d\n", __func__, segments); + } else { + printk(BIOS_ERR, "%s: not enough space in SMM to setup all CPUs\n", __func__); + printk(BIOS_ERR, " save state & stub size need to be reduced\n"); + printk(BIOS_ERR, " or increase SMRAM size\n"); + return 0; + } + + if (sizeof(cpus) / sizeof(struct cpu_smm_info) < num_cpus) { + printk(BIOS_ERR, + "%s: increase MAX_CPUS in Kconfig\n", __func__); + return 0; + } + + for (i = 0; i < num_cpus; i++) { + cpus[i].smbase = base; + cpus[i].entry = base + smm_entry_offset; + cpus[i].ss_start = cpus[i].entry + (smm_entry_offset - ss_size); + cpus[i].code_start = cpus[i].entry; + cpus[i].code_end = cpus[i].entry + stub_size; + cpus[i].active = 1; + base -= ss_size; + seg_count++; + if (seg_count >= cpus_in_segment) { + base -= smm_entry_offset; + seg_count = 0; + } + } + + if (CONFIG_DEFAULT_CONSOLE_LOGLEVEL >= BIOS_DEBUG) { + seg_count = 0; + for (i = 0; i < num_cpus; i++) { + printk(BIOS_DEBUG, "CPU 0x%x\n", i); + printk(BIOS_DEBUG, + " smbase %zx entry %zx\n", + cpus[i].smbase, cpus[i].entry); + printk(BIOS_DEBUG, + " ss_start %zx code_end %zx\n", + cpus[i].ss_start, cpus[i].code_end); + seg_count++; + if (seg_count >= cpus_in_segment) { + printk(BIOS_DEBUG, + "-------------NEW CODE SEGMENT --------------\n"); + seg_count = 0; + } + } + } + return 1; +} + +/* + * This method expects the smm relocation map to be complete. + * This method does not read any HW registers, it simply uses a + * map that was created during SMM setup. + * input: cpu_num - cpu number which is used as an index into the + * map to return the smbase + */ +u32 smm_get_cpu_smbase(unsigned int cpu_num) +{ + if (cpu_num < CONFIG_MAX_CPUS) { + if (cpus[cpu_num].active) + return cpus[cpu_num].smbase; + } + return 0; +} + +/* + * This method assumes that at least 1 CPU has been set up from + * which it will place other CPUs below its smbase ensuring that + * save state does not clobber the first CPUs init code segment. The init + * code which is the smm stub code is the same for all CPUs. They enter + * smm, setup stacks (based on their apic id), enter protected mode + * and then jump to the common smi handler. The stack is allocated + * at the beginning of smram (aka tseg base, not smbase). The stack + * pointer for each CPU is calculated by using its apic id + * (code is in smm_stub.s) + * Each entry point will now have the same stub code which, sets up the CPU + * stack, enters protected mode and then jumps to the smi handler. It is + * important to enter protected mode before the jump because the "jump to + * address" might be larger than the 20bit address supported by real mode. + * SMI entry right now is in real mode. + * input: smbase - this is the smbase of the first cpu not the smbase + * where tseg starts (aka smram_start). All CPUs code segment + * and stack will be below this point except for the common + * SMI handler which is one segment above + * input: num_cpus - number of cpus that need relocation including + * the first CPU (though its code is already loaded) + * input: top of stack (stacks work downward by default in Intel HW) + * output: return -1, if runtime smi code could not be installed. In + * this case SMM will not work and any SMI's generated will + * cause a CPU shutdown or general protection fault because + * the appropriate smi handling code was not installed + */ + +static int smm_place_entry_code(uintptr_t smbase, unsigned int num_cpus, + unsigned int stack_top, const struct smm_loader_params *params) +{ + unsigned int i; + unsigned int size; + if (smm_create_map(smbase, num_cpus, params)) { + /* + * Ensure there was enough space and the last CPUs smbase + * did not encroach upon the stack. Stack top is smram start + * + size of stack. + */ + if (cpus[num_cpus].active) { + if (cpus[num_cpus - 1].smbase + + params->smm_main_entry_offset < stack_top) { + printk(BIOS_ERR, "%s: stack encroachment\n", __func__); + printk(BIOS_ERR, "%s: smbase %zx, stack_top %x\n", + __func__, cpus[num_cpus].smbase, stack_top); + return 0; + } + } + } else { + printk(BIOS_ERR, "%s: unable to place smm entry code\n", __func__); + return 0; + } + + printk(BIOS_INFO, "%s: smbase %zx, stack_top %x\n", + __func__, cpus[num_cpus-1].smbase, stack_top); + + /* start at 1, the first CPU stub code is already there */ + size = cpus[0].code_end - cpus[0].code_start; + for (i = 1; i < num_cpus; i++) { + memcpy((int *)cpus[i].code_start, (int *)cpus[0].code_start, size); + printk(BIOS_DEBUG, + "SMM Module: placing smm entry code at %zx, cpu # 0x%x\n", + cpus[i].code_start, i); + printk(BIOS_DEBUG, "%s: copying from %zx to %zx 0x%x bytes\n", + __func__, cpus[0].code_start, cpus[i].code_start, size); + } + return 1; +} + +/* + * Place stacks in base -> base + size region, but ensure the stacks don't + * overlap the staggered entry points. + */ +static void *smm_stub_place_stacks(char *base, size_t size, + struct smm_loader_params *params) +{ + size_t total_stack_size; + char *stacks_top; + + /* If stack space is requested assume the space lives in the lower + * half of SMRAM. */ + total_stack_size = params->per_cpu_stack_size * + params->num_concurrent_stacks; + printk(BIOS_DEBUG, "%s: cpus: %zx : stack space: needed -> %zx\n", + __func__, params->num_concurrent_stacks, + total_stack_size); + printk(BIOS_DEBUG, " available -> %zx : per_cpu_stack_size : %zx\n", + size, params->per_cpu_stack_size); + + /* There has to be at least one stack user. */ + if (params->num_concurrent_stacks < 1) + return NULL; + + /* Total stack size cannot fit. */ + if (total_stack_size > size) + return NULL; + + /* Stacks extend down to SMBASE */ + stacks_top = &base[total_stack_size]; + printk(BIOS_DEBUG, "%s: exit, stack_top %p\n", __func__, stacks_top); + + return stacks_top; +} + +/* + * Place the staggered entry points for each CPU. The entry points are + * staggered by the per CPU SMM save state size extending down from + * SMM_ENTRY_OFFSET. + */ +static int smm_stub_place_staggered_entry_points(char *base, + const struct smm_loader_params *params, const struct rmodule *smm_stub) +{ + size_t stub_entry_offset; + int rc = 1; + stub_entry_offset = rmodule_entry_offset(smm_stub); + /* Each CPU now has its own stub code, which enters protected mode, + * sets up the stack, and then jumps to common SMI handler + */ + if (params->num_concurrent_save_states > 1 || stub_entry_offset != 0) { + rc = smm_place_entry_code((unsigned int)base, + params->num_concurrent_save_states, + (unsigned int)params->stack_top, params); + } + return rc; +} + +/* + * The stub setup code assumes it is completely contained within the + * default SMRAM size (0x10000) for the default SMI handler (entry at + * 0x30000), but no assumption should be made for the permanent SMI handler. + * The placement of CPU entry points for permanent handler are determined + * by the number of CPUs in the system and the amount of SMRAM. + * There are potentially 3 regions to place + * within the default SMRAM size: + * 1. Save state areas + * 2. Stub code + * 3. Stack areas + * + * The save state and smm stack are treated as contiguous for the number of + * concurrent areas requested. The save state always lives at the top of the + * the CPUS smbase (and the entry point is at offset 0x8000). This allows only a certain + * number of CPUs with staggered entry points until the save state area comes + * down far enough to overwrite/corrupt the entry code (stub code). Therefore, + * an SMM map is created to avoid this corruption, see smm_create_map() above. + * This module setup code works for the default (0x30000) SMM handler setup and the + * permanent SMM handler. + */ +static int smm_module_setup_stub(void *smbase, size_t smm_size, + struct smm_loader_params *params, + void *fxsave_area) +{ + size_t total_save_state_size; + size_t smm_stub_size; + size_t stub_entry_offset; + char *smm_stub_loc; + void *stacks_top; + size_t size; + char *base; + size_t i; + struct smm_stub_params *stub_params; + struct rmodule smm_stub; + unsigned int total_size_all; + base = smbase; + size = smm_size; + + /* The number of concurrent stacks cannot exceed CONFIG_MAX_CPUS. */ + if (params->num_concurrent_stacks > CONFIG_MAX_CPUS) { + printk(BIOS_ERR, "%s: not enough stacks\n", __func__); + return -1; + } + + /* Fail if can't parse the smm stub rmodule. */ + if (rmodule_parse(&_binary_smmstub_start, &smm_stub)) { + printk(BIOS_ERR, "%s: unable to parse smm stub\n", __func__); + return -1; + } + + /* Adjust remaining size to account for save state. */ + total_save_state_size = params->per_cpu_save_state_size * + params->num_concurrent_save_states; + if (total_save_state_size > size) { + printk(BIOS_ERR, + "%s: more state save space needed:need -> %zx:available->%zx\n", + __func__, total_save_state_size, size); + return -1; + } + + size -= total_save_state_size; + + /* The save state size encroached over the first SMM entry point. */ + if (size <= params->smm_main_entry_offset) { + printk(BIOS_ERR, "%s: encroachment over SMM entry point\n", __func__); + printk(BIOS_ERR, "%s: state save size: %zx : smm_entry_offset -> %x\n", + __func__, size, params->smm_main_entry_offset); + return -1; + } + + /* Need a minimum stack size and alignment. */ + if (params->per_cpu_stack_size <= SMM_MINIMUM_STACK_SIZE || + (params->per_cpu_stack_size & 3) != 0) { + printk(BIOS_ERR, "%s: need minimum stack size\n", __func__); + return -1; + } + + smm_stub_loc = NULL; + smm_stub_size = rmodule_memory_size(&smm_stub); + stub_entry_offset = rmodule_entry_offset(&smm_stub); + + /* Put the stub at the main entry point */ + smm_stub_loc = &base[params->smm_main_entry_offset]; + + /* Stub is too big to fit. */ + if (smm_stub_size > (size - params->smm_main_entry_offset)) { + printk(BIOS_ERR, "%s: stub is too big to fit\n", __func__); + return -1; + } + + /* The stacks, if requested, live in the lower half of SMRAM space + * for default handler, but for relocated handler it lives at the beginning + * of SMRAM which is TSEG base + */ + size = params->num_concurrent_stacks * params->per_cpu_stack_size; + stacks_top = smm_stub_place_stacks((char *)params->smram_start, size, params); + if (stacks_top == NULL) { + printk(BIOS_ERR, "%s: not enough space for stacks\n", __func__); + printk(BIOS_ERR, "%s: ....need -> %p : available -> %zx\n", __func__, + base, size); + return -1; + } + params->stack_top = stacks_top; + /* Load the stub. */ + if (rmodule_load(smm_stub_loc, &smm_stub)) { + printk(BIOS_ERR, "%s: load module failed\n", __func__); + return -1; + } + + if (!smm_stub_place_staggered_entry_points(base, params, &smm_stub)) { + printk(BIOS_ERR, "%s: staggered entry points failed\n", __func__); + return -1; + } + + /* Setup the parameters for the stub code. */ + stub_params = rmodule_parameters(&smm_stub); + stub_params->stack_top = (uintptr_t)stacks_top; + stub_params->stack_size = params->per_cpu_stack_size; + stub_params->c_handler = (uintptr_t)params->handler; + stub_params->c_handler_arg = (uintptr_t)params->handler_arg; + stub_params->fxsave_area = (uintptr_t)fxsave_area; + stub_params->fxsave_area_size = FXSAVE_SIZE; + stub_params->runtime.smbase = (uintptr_t)smbase; + stub_params->runtime.smm_size = smm_size; + stub_params->runtime.save_state_size = params->per_cpu_save_state_size; + stub_params->runtime.num_cpus = params->num_concurrent_stacks; + + printk(BIOS_DEBUG, "%s: stack_end = 0x%x\n", + __func__, stub_params->runtime.smbase); + printk(BIOS_DEBUG, + "%s: stack_top = 0x%x\n", __func__, stub_params->stack_top); + printk(BIOS_DEBUG, "%s: stack_size = 0x%x\n", + __func__, stub_params->stack_size); + printk(BIOS_DEBUG, "%s: runtime.smbase = 0x%x\n", + __func__, stub_params->runtime.smbase); + printk(BIOS_DEBUG, "%s: runtime.start32_offset = 0x%x\n", __func__, + stub_params->runtime.start32_offset); + printk(BIOS_DEBUG, "%s: runtime.smm_size = 0x%zx\n", + __func__, smm_size); + printk(BIOS_DEBUG, "%s: per_cpu_save_state_size = 0x%x\n", + __func__, stub_params->runtime.save_state_size); + printk(BIOS_DEBUG, "%s: num_cpus = 0x%x\n", __func__, + stub_params->runtime.num_cpus); + printk(BIOS_DEBUG, "%s: total_save_state_size = 0x%x\n", + __func__, (stub_params->runtime.save_state_size * + stub_params->runtime.num_cpus)); + total_size_all = stub_params->stack_size + + (stub_params->runtime.save_state_size * + stub_params->runtime.num_cpus); + printk(BIOS_DEBUG, "%s: total_size_all = 0x%x\n", __func__, + total_size_all); + + /* Initialize the APIC id to CPU number table to be 1:1 */ + for (i = 0; i < params->num_concurrent_stacks; i++) + stub_params->runtime.apic_id_to_cpu[i] = i; + + /* Allow the initiator to manipulate SMM stub parameters. */ + params->runtime = &stub_params->runtime; + + printk(BIOS_DEBUG, "SMM Module: stub loaded at %p. Will call %p(%p)\n", + smm_stub_loc, params->handler, params->handler_arg); + return 0; +} + +/* + * smm_setup_relocation_handler assumes the callback is already loaded in + * memory. i.e. Another SMM module isn't chained to the stub. The other + * assumption is that the stub will be entered from the default SMRAM + * location: 0x30000 -> 0x40000. + */ +int smm_setup_relocation_handler(struct smm_loader_params *params) +{ + void *smram = (void *)(SMM_DEFAULT_BASE); + printk(BIOS_SPEW, "%s: enter\n", __func__); + /* There can't be more than 1 concurrent save state for the relocation + * handler because all CPUs default to 0x30000 as SMBASE. */ + if (params->num_concurrent_save_states > 1) + return -1; + + /* A handler has to be defined to call for relocation. */ + if (params->handler == NULL) + return -1; + + /* Since the relocation handler always uses stack, adjust the number + * of concurrent stack users to be CONFIG_MAX_CPUS. */ + if (params->num_concurrent_stacks == 0) + params->num_concurrent_stacks = CONFIG_MAX_CPUS; + + params->smm_main_entry_offset = SMM_ENTRY_OFFSET; + params->smram_start = SMM_DEFAULT_BASE; + params->smram_end = SMM_DEFAULT_BASE + SMM_DEFAULT_SIZE; + return smm_module_setup_stub(smram, SMM_DEFAULT_SIZE, + params, fxsave_area_relocation); + printk(BIOS_SPEW, "%s: exit\n", __func__); +} + +/* + *The SMM module is placed within the provided region in the following + * manner: + * +-----------------+ <- smram + size + * | BIOS resource | + * | list (STM) | + * +-----------------+ + * | fxsave area | + * +-----------------+ + * | smi handler | + * | ... | + * +-----------------+ <- cpu0 + * | stub code | <- cpu1 + * | stub code | <- cpu2 + * | stub code | <- cpu3, etc + * | | + * | | + * | | + * | stacks | + * +-----------------+ <- smram start + + * It should be noted that this algorithm will not work for + * SMM_DEFAULT_SIZE SMRAM regions such as the A segment. This algorithm + * expects a region large enough to encompass the handler and stacks + * as well as the SMM_DEFAULT_SIZE. + */ +int smm_load_module(void *smram, size_t size, struct smm_loader_params *params) +{ + struct rmodule smm_mod; + size_t total_stack_size; + size_t handler_size; + size_t module_alignment; + size_t alignment_size; + size_t fxsave_size; + void *fxsave_area; + size_t total_size = 0; + char *base; + + if (size <= SMM_DEFAULT_SIZE) + return -1; + + /* Load main SMI handler at the top of SMRAM + * everything else will go below + */ + base = smram; + base += size; + params->smram_start = (uintptr_t)smram; + params->smram_end = params->smram_start + size; + params->smm_main_entry_offset = SMM_ENTRY_OFFSET; + + /* Fail if can't parse the smm rmodule. */ + if (rmodule_parse(&_binary_smm_start, &smm_mod)) + return -1; + + /* Clear SMM region */ + if (CONFIG(DEBUG_SMI)) + memset(smram, 0xcd, size); + + total_stack_size = params->per_cpu_stack_size * + params->num_concurrent_stacks; + total_size += total_stack_size; + /* Stacks are the base of SMRAM */ + params->stack_top = smram + total_stack_size; + + /* MSEG starts at the top of SMRAM and works down */ + if (CONFIG(STM)) { + base -= CONFIG_MSEG_SIZE + CONFIG_BIOS_RESOURCE_LIST_SIZE; + total_size += CONFIG_MSEG_SIZE + CONFIG_BIOS_RESOURCE_LIST_SIZE; + } + + /* FXSAVE goes below MSEG */ + if (CONFIG(SSE)) { + fxsave_size = FXSAVE_SIZE * params->num_concurrent_stacks; + fxsave_area = base - fxsave_size; + base -= fxsave_size; + total_size += fxsave_size; + } else { + fxsave_size = 0; + fxsave_area = NULL; + } + + + handler_size = rmodule_memory_size(&smm_mod); + base -= handler_size; + total_size += handler_size; + module_alignment = rmodule_load_alignment(&smm_mod); + alignment_size = module_alignment - + ((uintptr_t)base % module_alignment); + if (alignment_size != module_alignment) { + handler_size += alignment_size; + base += alignment_size; + } + + printk(BIOS_DEBUG, + "%s: total_smm_space_needed %zx, available -> %zx\n", + __func__, total_size, size); + + /* Does the required amount of memory exceed the SMRAM region size? */ + if (total_size > size) { + printk(BIOS_ERR, "%s: need more SMRAM\n", __func__); + return -1; + } + if (handler_size > SMM_CODE_SEGMENT_SIZE) { + printk(BIOS_ERR, "%s: increase SMM_CODE_SEGMENT_SIZE: handler_size = %zx\n", + __func__, handler_size); + return -1; + } + + if (rmodule_load(base, &smm_mod)) + return -1; + + params->handler = rmodule_entry(&smm_mod); + params->handler_arg = rmodule_parameters(&smm_mod); + + printk(BIOS_DEBUG, "%s: smram_start: 0x%p\n", + __func__, smram); + printk(BIOS_DEBUG, "%s: smram_end: %p\n", + __func__, smram + size); + printk(BIOS_DEBUG, "%s: stack_top: %p\n", + __func__, params->stack_top); + 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: handler_arg %p\n", + __func__, params->handler_arg); + printk(BIOS_DEBUG, "%s: fxsave_area %p\n", + __func__, fxsave_area); + printk(BIOS_DEBUG, "%s: fxsave_size %zx\n", + __func__, fxsave_size); + printk(BIOS_DEBUG, "%s: CONFIG_MSEG_SIZE 0x%x\n", + __func__, CONFIG_MSEG_SIZE); + printk(BIOS_DEBUG, "%s: CONFIG_BIOS_RESOURCE_LIST_SIZE 0x%x\n", + __func__, CONFIG_BIOS_RESOURCE_LIST_SIZE); + + /* CPU 0 smbase goes first, all other CPUs + * will be staggered below + */ + base -= SMM_CODE_SEGMENT_SIZE; + printk(BIOS_DEBUG, "%s: cpu0 entry: %p\n", + __func__, base); + params->smm_entry = (uintptr_t)base + params->smm_main_entry_offset; + return smm_module_setup_stub(base, size, params, fxsave_area); +} diff --git a/src/include/cpu/x86/smm.h b/src/include/cpu/x86/smm.h index 26496eebac..d8f6d0e627 100644 --- a/src/include/cpu/x86/smm.h +++ b/src/include/cpu/x86/smm.h @@ -118,6 +118,12 @@ void *smm_get_save_state(int cpu); * into this field so the code doing the loading can manipulate the * runtime's assumptions. e.g. updating the APIC id to CPU map to * handle sparse APIC id space. + * The following parameters are only used when X86_SMM_LOADER_VERSION2 is enabled. + * - smm_entry - entry address of first CPU thread, all others will be tiled + * below this address. + * - smm_main_entry_offset - default entry offset (e.g 0x8000) + * - smram_start - smaram starting address + * - smram_end - smram ending address */ struct smm_loader_params { void *stack_top; @@ -131,12 +137,24 @@ struct smm_loader_params { void *handler_arg; struct smm_runtime *runtime; + + /* The following are only used by X86_SMM_LOADER_VERSION2 */ +#if CONFIG(X86_SMM_LOADER_VERSION2) + unsigned int smm_entry; + unsigned int smm_main_entry_offset; + unsigned int smram_start; + unsigned int smram_end; +#endif }; /* Both of these return 0 on success, < 0 on failure. */ int smm_setup_relocation_handler(struct smm_loader_params *params); int smm_load_module(void *smram, size_t size, struct smm_loader_params *params); +#if CONFIG(X86_SMM_LOADER_VERSION2) +u32 smm_get_cpu_smbase(unsigned int cpu_num); +#endif + /* Backup and restore default SMM region. */ void *backup_default_smm_area(void); void restore_default_smm_area(void *smm_save_area); From 6f1a75950aa0a8d908803b197c4c8dcc6956e136 Mon Sep 17 00:00:00 2001 From: Marc Jones Date: Fri, 5 Feb 2021 10:53:55 -0700 Subject: [PATCH 34/67] soc/intel/fsp_broadwell_de: Use smm_module_loaderv2 Use smm_module_loaderv2 to support 16core/32thread Broadwell_DE. Tested SMM handler loads on all 32 threads. Change-Id: I3a6e17e8590a2af9b4e7c701f8fccfccfa3ea94b Signed-off-by: Marc Jones Reviewed-on: https://review.coreboot.org/c/coreboot/+/50314 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer Reviewed-by: Jay Talbott --- src/soc/intel/fsp_broadwell_de/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/src/soc/intel/fsp_broadwell_de/Kconfig b/src/soc/intel/fsp_broadwell_de/Kconfig index 4c45f29618..0186e85d13 100644 --- a/src/soc/intel/fsp_broadwell_de/Kconfig +++ b/src/soc/intel/fsp_broadwell_de/Kconfig @@ -23,6 +23,7 @@ config CPU_SPECIFIC_OPTIONS select SUPPORT_CPU_UCODE_IN_CBFS select INTEL_DESCRIPTOR_MODE_CAPABLE select HAVE_SMI_HANDLER + select X86_SMM_LOADER_VERSION2 select TSC_MONOTONIC_TIMER select HAVE_FSP_BIN select CPU_INTEL_FIRMWARE_INTERFACE_TABLE From 413027b0c732dc4406835de0ede4a79de3bd9f85 Mon Sep 17 00:00:00 2001 From: Marc Jones Date: Thu, 11 Feb 2021 11:13:51 -0700 Subject: [PATCH 35/67] mainboard/ocp/monolake: Remove ACPI PNP0C0C device Remove the empty PWRB ACPI device. The power button is controlled by the fixed power button model in PM1x_EVT_BLK and doesn't have a control method. The only device in mainboard.asl was PWRB, so remove the file. This fixes the FWTS error: acpi_pwrb: PWR_Button field in FACP should not be zero with ACPI PNP0C0C device. Change-Id: Idd8c3588694b913b52ca6509332603e3525117b7 Signed-off-by: Marc Jones Reviewed-on: https://review.coreboot.org/c/coreboot/+/50569 Tested-by: build bot (Jenkins) Reviewed-by: Jay Talbott Reviewed-by: Paul Menzel Reviewed-by: Angel Pons --- src/mainboard/ocp/monolake/acpi/mainboard.asl | 20 ------------------- src/mainboard/ocp/monolake/dsdt.asl | 2 -- 2 files changed, 22 deletions(-) delete mode 100644 src/mainboard/ocp/monolake/acpi/mainboard.asl diff --git a/src/mainboard/ocp/monolake/acpi/mainboard.asl b/src/mainboard/ocp/monolake/acpi/mainboard.asl deleted file mode 100644 index 62944ef353..0000000000 --- a/src/mainboard/ocp/monolake/acpi/mainboard.asl +++ /dev/null @@ -1,20 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2012 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. - */ - -Device (PWRB) -{ - Name(_HID, EisaId("PNP0C0C")) -} diff --git a/src/mainboard/ocp/monolake/dsdt.asl b/src/mainboard/ocp/monolake/dsdt.asl index 0d9e90dab3..5fe9d44f7e 100644 --- a/src/mainboard/ocp/monolake/dsdt.asl +++ b/src/mainboard/ocp/monolake/dsdt.asl @@ -40,6 +40,4 @@ DefinitionBlock( #include } - - #include "acpi/mainboard.asl" } From 236ca58a76d840b22103272fbdfeebc8d2404c4d Mon Sep 17 00:00:00 2001 From: Marc Jones Date: Fri, 19 Feb 2021 10:42:20 -0700 Subject: [PATCH 36/67] 3rdparty/intel-microcode: Update to 2020118 release Update the 4.11_branch to the 2020118 intel microcde release, which is the current main HEAD. Change-Id: Ic010594a59b692b18eb40656c283c080c34c4d2c Signed-off-by: Marc Jones Reviewed-on: https://review.coreboot.org/c/coreboot/+/50553 Reviewed-by: Jay Talbott Reviewed-by: Patrick Georgi Tested-by: build bot (Jenkins) --- 3rdparty/intel-microcode | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdparty/intel-microcode b/3rdparty/intel-microcode index 1dd14da6d1..49bb67f32a 160000 --- a/3rdparty/intel-microcode +++ b/3rdparty/intel-microcode @@ -1 +1 @@ -Subproject commit 1dd14da6d1ea5cfbd95923653f31c04aac3aa655 +Subproject commit 49bb67f32a2e3e631ba1a9a73da1c52e1cac7fd9 From 8916d124269ffa5d1d3c19e3f6b19615dd86b66c Mon Sep 17 00:00:00 2001 From: Jonathan Zhang Date: Thu, 4 Mar 2021 10:59:20 -0800 Subject: [PATCH 37/67] mb/facebook/watson: include variant subdirectory watson_v2 mainboard variant has its own code to be built in. Update Makefile.inc of mainboard directory to include variant subdirectory. Signed-off-by: Jonathan Zhang Change-Id: I21ee1c575b3b6e4278955c12d6e4f7109eb75105 Reviewed-on: https://review.coreboot.org/c/coreboot/+/51308 Reviewed-by: Angel Pons Reviewed-by: Christian Walter Tested-by: build bot (Jenkins) --- src/mainboard/facebook/watson/Makefile.inc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mainboard/facebook/watson/Makefile.inc b/src/mainboard/facebook/watson/Makefile.inc index f1384f7c97..ecad3e74aa 100644 --- a/src/mainboard/facebook/watson/Makefile.inc +++ b/src/mainboard/facebook/watson/Makefile.inc @@ -15,4 +15,5 @@ ramstage-y += irqroute.c +subdirs-y += variants/$(VARIANT_DIR) CPPFLAGS_common += -I$(src)/mainboard/$(MAINBOARDDIR)/include From 2f32b5b5d0e0803ca1782d285f16cfae030c89d0 Mon Sep 17 00:00:00 2001 From: Jonathan Zhang Date: Mon, 22 Feb 2021 12:13:38 -0800 Subject: [PATCH 38/67] soc/intel/fsp_broadwell_de: add PCH_DEV_LPC definition Signed-off-by: Jonathan Zhang Change-Id: I2292bf1f6b5d17f95f8e8e41c6d9f07781f22576 Reviewed-on: https://review.coreboot.org/c/coreboot/+/51309 Reviewed-by: Angel Pons Reviewed-by: Christian Walter Tested-by: build bot (Jenkins) --- src/soc/intel/fsp_broadwell_de/include/soc/pci_devs.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/soc/intel/fsp_broadwell_de/include/soc/pci_devs.h b/src/soc/intel/fsp_broadwell_de/include/soc/pci_devs.h index 6a68b2f81f..ba5c1deeed 100644 --- a/src/soc/intel/fsp_broadwell_de/include/soc/pci_devs.h +++ b/src/soc/intel/fsp_broadwell_de/include/soc/pci_devs.h @@ -56,6 +56,7 @@ #define LPC_DEV 31 #define LPC_FUNC 0 #define PCH_DEVFN_LPC PCI_DEVFN(LPC_DEV, LPC_FUNC) +#define PCH_DEV_LPC PCI_DEV(BUS0, LPC_DEV, LPC_FUNC) #define SATA_DEV 31 #define SATA_FUNC 2 From 019c0049a27c7eea0b92e8e5af3e5fb992beb315 Mon Sep 17 00:00:00 2001 From: Jonathan Zhang Date: Mon, 22 Feb 2021 12:17:30 -0800 Subject: [PATCH 39/67] mb/fb/watson: enable IPMI_KCS for watson_v2 For watson_v2 mainboard variant: * Enable IPMI_KCS in config. * In early_mainboard_romstage_entry(), enable LPC IO ports for IPMI over KCS. Signed-off-by: Ravi Rama Signed-off-by: Jonathan Zhang Change-Id: Ie0e718b44889678c49f3d61cccd0e33b306fc6f3 Reviewed-on: https://review.coreboot.org/c/coreboot/+/51310 Reviewed-by: Angel Pons Reviewed-by: Christian Walter Tested-by: build bot (Jenkins) --- src/mainboard/facebook/watson/Kconfig | 1 + src/mainboard/facebook/watson/include/variants.h | 1 + src/mainboard/facebook/watson/romstage.c | 7 ++++++- .../facebook/watson/variants/watson_v2/romstage.c | 12 ++++++++++++ 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/mainboard/facebook/watson/Kconfig b/src/mainboard/facebook/watson/Kconfig index 2ebc0206cf..919117d653 100644 --- a/src/mainboard/facebook/watson/Kconfig +++ b/src/mainboard/facebook/watson/Kconfig @@ -16,6 +16,7 @@ config BOARD_SPECIFIC_OPTIONS select HAVE_ACPI_TABLES select HAVE_OPTION_TABLE select INTEGRATED_UART + select IPMI_KCS if BOARD_FACEBOOK_WATSON_V2 select SERIRQ_CONTINUOUS_MODE select MAINBOARD_USES_IFD_GBE_REGION select MAINBOARD_HAS_LPC_TPM diff --git a/src/mainboard/facebook/watson/include/variants.h b/src/mainboard/facebook/watson/include/variants.h index 46989168c9..d364b8b007 100644 --- a/src/mainboard/facebook/watson/include/variants.h +++ b/src/mainboard/facebook/watson/include/variants.h @@ -21,5 +21,6 @@ #include void variant_romstage_fsp_init_params(UPD_DATA_REGION *UpdData); +void variant_early_mainboard_romstage_entry(void); #endif /* BASEBOARD_VARIANTS_H */ diff --git a/src/mainboard/facebook/watson/romstage.c b/src/mainboard/facebook/watson/romstage.c index b8df798031..d65ac0ef51 100644 --- a/src/mainboard/facebook/watson/romstage.c +++ b/src/mainboard/facebook/watson/romstage.c @@ -25,7 +25,7 @@ */ void early_mainboard_romstage_entry(void) { - + variant_early_mainboard_romstage_entry(); } /** @@ -52,3 +52,8 @@ __weak void variant_romstage_fsp_init_params(UPD_DATA_REGION *UpdData) { } + +__weak void variant_early_mainboard_romstage_entry(void) +{ + +} diff --git a/src/mainboard/facebook/watson/variants/watson_v2/romstage.c b/src/mainboard/facebook/watson/variants/watson_v2/romstage.c index 55f30255e8..2e571b9713 100644 --- a/src/mainboard/facebook/watson/variants/watson_v2/romstage.c +++ b/src/mainboard/facebook/watson/variants/watson_v2/romstage.c @@ -15,6 +15,9 @@ * GNU General Public License for more details. */ +#include +#include +#include #include #include @@ -46,3 +49,12 @@ void variant_romstage_fsp_init_params(UPD_DATA_REGION *UpdData) UpdData->HotPlug_PchPciPort7 = 1; UpdData->HotPlug_PchPciPort8 = 1; } + +void variant_early_mainboard_romstage_entry(void) +{ + // Enable LPC IO ports 0xca2, 0xca8 for IPMI + pci_write_config32(PCH_DEV_LPC, LPC_GEN2_DEC, + (0 << 16) | ALIGN_DOWN(0xca2, 4) | 1); + pci_write_config32(PCH_DEV_LPC, LPC_GEN3_DEC, + (0 << 16) | ALIGN_DOWN(0xca8, 4) | 1); +} From 570ae23516593e243e29750f4b61a1b841a5ad27 Mon Sep 17 00:00:00 2001 From: Jonathan Zhang Date: Tue, 2 Mar 2021 09:01:59 -0800 Subject: [PATCH 40/67] mb/facebook/watson/v2: enable IPMI to be detected as PNP device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Watson v2 mainboard has hardware support and OpenBMC support for IPMI. Add drivers/ipmi to the device tree of watson v2 mainboard. Use original device tree for watson mainboard. TESTED=booted watson v2 board, and tested ipmitool command:    0 | OEM record fb | 2800000000f0ffffffffffffff Signed-off-by: Ravi Rama Signed-off-by: Jonathan Zhang Change-Id: I1be653278dbfd704d24756cf82be73bdae4bb13c Reviewed-on: https://review.coreboot.org/c/coreboot/+/51311 Reviewed-by: Angel Pons Reviewed-by: Christian Walter Tested-by: build bot (Jenkins) --- src/mainboard/facebook/watson/Kconfig | 5 ++++ .../{ => variants/watson}/devicetree.cb | 0 .../watson/variants/watson_v2/devicetree.cb | 23 +++++++++++++++++++ 3 files changed, 28 insertions(+) rename src/mainboard/facebook/watson/{ => variants/watson}/devicetree.cb (100%) create mode 100644 src/mainboard/facebook/watson/variants/watson_v2/devicetree.cb diff --git a/src/mainboard/facebook/watson/Kconfig b/src/mainboard/facebook/watson/Kconfig index 919117d653..668b0ba66f 100644 --- a/src/mainboard/facebook/watson/Kconfig +++ b/src/mainboard/facebook/watson/Kconfig @@ -37,6 +37,10 @@ config MAINBOARD_PART_NUMBER string default "Watson" +config DEVICETREE + string + default "variants/$(CONFIG_VARIANT_DIR)/devicetree.cb" + config IRQ_SLOT_COUNT int default 18 @@ -47,6 +51,7 @@ config CBFS_SIZE config VARIANT_DIR string + default "watson" if BOARD_FACEBOOK_WATSON default "watson_v2" if BOARD_FACEBOOK_WATSON_V2 config VBOOT_FWID_MODEL diff --git a/src/mainboard/facebook/watson/devicetree.cb b/src/mainboard/facebook/watson/variants/watson/devicetree.cb similarity index 100% rename from src/mainboard/facebook/watson/devicetree.cb rename to src/mainboard/facebook/watson/variants/watson/devicetree.cb diff --git a/src/mainboard/facebook/watson/variants/watson_v2/devicetree.cb b/src/mainboard/facebook/watson/variants/watson_v2/devicetree.cb new file mode 100644 index 0000000000..276dea0c8b --- /dev/null +++ b/src/mainboard/facebook/watson/variants/watson_v2/devicetree.cb @@ -0,0 +1,23 @@ +chip soc/intel/fsp_broadwell_de + device cpu_cluster 0 on + device lapic 0 on end + end + device domain 0 on + device pci 00.0 on end # SoC router + device pci 14.0 on end # xHCI Controller + device pci 19.0 on end # Gigabit LAN Controller + device pci 1d.0 on end # EHCI Controller + device pci 1f.0 on # LPC Bridge + chip drivers/pc80/tpm + device pnp 0c31.0 on end + end + chip drivers/ipmi + device pnp ca2.0 on end + register "bmc_i2c_address" = "0x20" + end + end + device pci 1f.2 on end # SATA Controller + device pci 1f.3 on end # SMBus Controller + device pci 1f.5 on end # SATA Controller + end +end From 8b22c558554c3722cbd809fac132a5ca46451280 Mon Sep 17 00:00:00 2001 From: Jonathan Zhang Date: Mon, 22 Mar 2021 16:12:05 -0700 Subject: [PATCH 41/67] soc/intel/fsp_broadwell_de: Add definition for LGMR Add definition for LPC Generic Memory Range register. Signed-off-by: Jonathan Zhang Change-Id: I7c76bacdf692e72849547106f29b614345f505c1 Reviewed-on: https://review.coreboot.org/c/coreboot/+/51716 Reviewed-by: Angel Pons Tested-by: build bot (Jenkins) --- src/soc/intel/fsp_broadwell_de/include/soc/lpc.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/soc/intel/fsp_broadwell_de/include/soc/lpc.h b/src/soc/intel/fsp_broadwell_de/include/soc/lpc.h index 3f9c2024f7..01e5a5b28d 100644 --- a/src/soc/intel/fsp_broadwell_de/include/soc/lpc.h +++ b/src/soc/intel/fsp_broadwell_de/include/soc/lpc.h @@ -37,6 +37,7 @@ #define LPC_GEN2_DEC 0x88 #define LPC_GEN3_DEC 0x8c #define LPC_GEN4_DEC 0x90 +#define LGMR 0x98 /* LPC Generic Memory Range */ #define GEN_PMCON_1 0xA0 #define SMI_LOCK (1 << 4) #define SMI_LOCK_GP6 (1 << 5) From 9f53477768156bfe29403f6facc10552e53a2d64 Mon Sep 17 00:00:00 2001 From: Jonathan Zhang Date: Mon, 22 Mar 2021 16:23:38 -0700 Subject: [PATCH 42/67] soc/intel/fsp_broadwell_de: Set up LPC Generic Memory Range register If mainboard devicetree config defines lpc_lgmr, use it to set up LPC Generic Memory Range register. Also set up 64KiB memory resource. Signed-off-by: Jonathan Zhang Change-Id: Iec94f7364c332789f75c2562e910ea5db4ffad23 Reviewed-on: https://review.coreboot.org/c/coreboot/+/51717 Reviewed-by: Angel Pons Tested-by: build bot (Jenkins) --- src/soc/intel/fsp_broadwell_de/chip.h | 2 ++ src/soc/intel/fsp_broadwell_de/southcluster.c | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/src/soc/intel/fsp_broadwell_de/chip.h b/src/soc/intel/fsp_broadwell_de/chip.h index bf2896238a..95c1c2d959 100644 --- a/src/soc/intel/fsp_broadwell_de/chip.h +++ b/src/soc/intel/fsp_broadwell_de/chip.h @@ -25,6 +25,8 @@ struct soc_intel_fsp_broadwell_de_config { /* PCIe completion timeout value */ int pcie_compltoval; + /* LPC Generic Memory Range Register value */ + uint32_t lpc_lgmr; }; typedef struct soc_intel_fsp_broadwell_de_config config_t; diff --git a/src/soc/intel/fsp_broadwell_de/southcluster.c b/src/soc/intel/fsp_broadwell_de/southcluster.c index fb8af87b62..df562f133d 100644 --- a/src/soc/intel/fsp_broadwell_de/southcluster.c +++ b/src/soc/intel/fsp_broadwell_de/southcluster.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -216,6 +217,17 @@ static void sc_read_resources(struct device *dev) pci_dev_read_resources(dev); sc_add_mmio_resources(dev); sc_add_io_resources(dev); + + const config_t *config = config_of_soc(); + if (config->lpc_lgmr) { + struct resource *res; + res = new_resource(dev, LGMR); + res->base = config->lpc_lgmr & ~(LPC_LGMR_EN); + res->size = 64 * KiB; + res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED + | IORESOURCE_RESERVE; + pci_write_config32(dev, LGMR, config->lpc_lgmr); + } } static void sc_init(struct device *dev) From da2827949eb108381068272354b9f92f39b84086 Mon Sep 17 00:00:00 2001 From: Jonathan Zhang Date: Mon, 22 Mar 2021 16:27:56 -0700 Subject: [PATCH 43/67] mb/facebook/watson/v2: Reserve memory region for CPLD access For watson_v2 variant, add lpc_lgmr register in device tree configuration to access CPLD regsiters. TESTED=booted watson_v2 server into target OS, confirm CPLD register access: devmem2 0xB0000100 Value at address 0xb0000100: 0x00020003 Signed-off-by: Jonathan Zhang Signed-off-by: Ravi Rama Change-Id: I43ee89b8609c64bccf5a21171d8ff192e6aca0ef Reviewed-on: https://review.coreboot.org/c/coreboot/+/51718 Reviewed-by: Angel Pons Tested-by: build bot (Jenkins) --- src/mainboard/facebook/watson/variants/watson_v2/devicetree.cb | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mainboard/facebook/watson/variants/watson_v2/devicetree.cb b/src/mainboard/facebook/watson/variants/watson_v2/devicetree.cb index 276dea0c8b..e019a4eb2c 100644 --- a/src/mainboard/facebook/watson/variants/watson_v2/devicetree.cb +++ b/src/mainboard/facebook/watson/variants/watson_v2/devicetree.cb @@ -1,4 +1,5 @@ chip soc/intel/fsp_broadwell_de + register "lpc_lgmr" = "0xb0000001" # CPLD device cpu_cluster 0 on device lapic 0 on end end From bf2f0757a7001a06eb12820d143d6420b5af7ffb Mon Sep 17 00:00:00 2001 From: Marc Jones Date: Sun, 23 May 2021 11:40:51 -0600 Subject: [PATCH 44/67] src/soc/intel/fsp_boradwell_de: Update ACPI FADT GPE entries Update the FADT for fwts errors for the GPE entries. Fix GPE0 access size and remove GPE1 address space ID. Change-Id: Iea43b534fa119d17cb2bafef8f72d73bcba3a650 Signed-off-by: Marc Jones Reviewed-on: https://review.coreboot.org/c/coreboot/+/54879 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer --- src/soc/intel/fsp_broadwell_de/acpi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/soc/intel/fsp_broadwell_de/acpi.c b/src/soc/intel/fsp_broadwell_de/acpi.c index 5349c30758..498aee1711 100644 --- a/src/soc/intel/fsp_broadwell_de/acpi.c +++ b/src/soc/intel/fsp_broadwell_de/acpi.c @@ -271,11 +271,11 @@ void acpi_fill_in_fadt(acpi_fadt_t *fadt, acpi_facs_t *facs, void *dsdt) fadt->x_gpe0_blk.space_id = ACPI_ADDRESS_SPACE_IO; fadt->x_gpe0_blk.bit_width = 64; /* EventStatus + EventEnable */ fadt->x_gpe0_blk.bit_offset = 0; - fadt->x_gpe0_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS; + fadt->x_gpe0_blk.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS; fadt->x_gpe0_blk.addrl = fadt->gpe0_blk; fadt->x_gpe0_blk.addrh = 0x00; - fadt->x_gpe1_blk.space_id = ACPI_ADDRESS_SPACE_IO; + fadt->x_gpe1_blk.space_id = 0; fadt->x_gpe1_blk.bit_width = 0; fadt->x_gpe1_blk.bit_offset = 0; fadt->x_gpe1_blk.access_size = 0; From 4a3e7dd31d090272d2b11bb8c48aa8bad09a3760 Mon Sep 17 00:00:00 2001 From: Marc Jones Date: Sun, 23 May 2021 12:17:54 -0600 Subject: [PATCH 45/67] src/mainboard/ocp/monolake: Set end of post GPIO Set the end of post GPIO to the BMC. This gets IPMI working on the BMC. Change-Id: I1a0055cdfd4a973b5f42570723bd95f1844dd9a7 Signed-off-by: Marc Jones Reviewed-on: https://review.coreboot.org/c/coreboot/+/54880 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer --- src/mainboard/ocp/monolake/mainboard.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/mainboard/ocp/monolake/mainboard.c b/src/mainboard/ocp/monolake/mainboard.c index 5f3408ec77..7887bae5c4 100644 --- a/src/mainboard/ocp/monolake/mainboard.c +++ b/src/mainboard/ocp/monolake/mainboard.c @@ -14,6 +14,7 @@ * GNU General Public License for more details. */ +#include #include #include #include @@ -22,6 +23,7 @@ #include #include #include +#include #include "ipmi.h" /* VPD variable for enabling/disabling FRB2 timer. */ #define FRB2_TIMER "FRB2_TIMER" @@ -232,3 +234,13 @@ const char *smbios_mainboard_serial_number(void) else return CONFIG_MAINBOARD_SERIAL_NUMBER; } + +/* Set the BMC BIOS POST complete GPIO (FM_BIOS_POST_CMPLT_N) on payload load. */ +static void bmc_set_post_complete_gpio_callback(void *arg) +{ + /* GPIO 46 FM_BIOS_POST_CMPLT_N */ + gpio_set(46, 0); + printk(BIOS_DEBUG, "BMC: POST complete gpio set\n"); +} + +BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_BOOT, BS_ON_ENTRY, bmc_set_post_complete_gpio_callback, NULL); From 463aee755ed1ac94c8c433fcfad6302cf37f22fb Mon Sep 17 00:00:00 2001 From: Marc Jones Date: Mon, 24 May 2021 11:16:30 -0600 Subject: [PATCH 46/67] mainboard/ocp/monolake: Clean up devicetree.cb Clean up the device tree as noted by the coreboot log. PCI: Leftover static devices: PCI: 00:02.2 PCI: 00:02.3 PCI: 00:19.0 PCI: 00:1d.0 PCI: 00:1f.5 PCI: Check your devicetree.cb. PCI: 00:02.2 - Keep - "off" setting disables the root port PCI: 00:02.3 - Remove - there is no 2.3 root port PCI: 00:19.0 - Remove - Gigabit controller is disabled on Mono Lake PCI: 00:1d.0 - Keep - EHCI enable patch to follow PCI: 00:1f.5 - Remove - Second SATA device not enabled Change-Id: I200acdda07f6bd6a060de3c4b4d335d9227216ed Signed-off-by: Marc Jones Reviewed-on: https://review.coreboot.org/c/coreboot/+/54881 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer --- src/mainboard/ocp/monolake/devicetree.cb | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/mainboard/ocp/monolake/devicetree.cb b/src/mainboard/ocp/monolake/devicetree.cb index 26c95d5d67..0e3857b1de 100644 --- a/src/mainboard/ocp/monolake/devicetree.cb +++ b/src/mainboard/ocp/monolake/devicetree.cb @@ -5,9 +5,7 @@ chip soc/intel/fsp_broadwell_de device domain 0 on device pci 00.0 on end # SoC router device pci 02.2 off end # IOU0 port C, 10GbE - device pci 02.3 off end # IOU0 port D, 10GbE device pci 14.0 on end # xHCI Controller - device pci 19.0 on end # Gigabit LAN Controller device pci 1d.0 on end # EHCI Controller device pci 1f.0 on chip drivers/pc80/tpm @@ -20,6 +18,5 @@ chip soc/intel/fsp_broadwell_de end # LPC Bridge device pci 1f.2 on end # SATA Controller device pci 1f.3 on end # SMBus Controller - device pci 1f.5 on end # SATA Controller end end From 3ec21b07fb9cb27f76ce515d265d7f73d66ba08a Mon Sep 17 00:00:00 2001 From: Werner Zeh Date: Tue, 8 Jun 2021 09:49:19 +0200 Subject: [PATCH 47/67] .gitmodules: Update intel-microcode submodule to track branch=main The 3rdparty submodule 'intel-microcode' has changed the branch from 'master' to 'main'. As we do not set any specific branch name in our config, it defaults to 'master' which makes "git submodule update --remote --rebase 3rdparty/intel-microcode" to fail. This patch adds the branch name in .gitmodules to match the upstream name. Change-Id: I7b6d7921a21af4eb3bcc7ce4e5a8ea21c38c89a3 Signed-off-by: Werner Zeh Reviewed-on: https://review.coreboot.org/c/coreboot/+/55305 Tested-by: build bot (Jenkins) Reviewed-by: Mario Scheithauer Reviewed-by: Marc Jones --- .gitmodules | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitmodules b/.gitmodules index 010ab6b49d..1b47275290 100644 --- a/.gitmodules +++ b/.gitmodules @@ -34,6 +34,7 @@ url = ../intel-microcode.git update = none ignore = dirty + branch = main [submodule "3rdparty/ffs"] path = 3rdparty/ffs url = ../ffs.git From 1d3fbda9ee6551f2453abfb88ba79d30e50d6249 Mon Sep 17 00:00:00 2001 From: Marc Jones Date: Fri, 16 Apr 2021 14:26:08 -0600 Subject: [PATCH 48/67] src/drivers/ipmi: Add DEBUG_IPMI option IPMI debug was extra spewy, so add a debug option as SPI and other drivers have when they need to be debugged. Original-Signed-off-by: Marc Jones Original-Reviewed-on: https://review.coreboot.org/c/coreboot/+/52449 Original-Tested-by: build bot (Jenkins) Original-Reviewed-by: Angel Pons (cherry picked from commit dc12daf277d9e94a8acfe8ad875bd38ebca897ba) Change-Id: If586b5feea74de0e6ed677af18e61dedf1216939 Signed-off-by: Marc Jones Reviewed-on: https://review.coreboot.org/c/coreboot/+/54878 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer --- src/Kconfig | 7 +++++++ src/drivers/ipmi/ipmi_kcs.c | 12 ++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/Kconfig b/src/Kconfig index c0315239fc..43b92a0130 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -1031,6 +1031,13 @@ config DEBUG_SPI_FLASH help This option enables additional SPI flash related debug messages. +config DEBUG_IPMI + bool "Output verbose IPMI debug messages" + default n + depends on IPMI_KCS + help + This option enables additional IPMI related debug messages. + if SOUTHBRIDGE_INTEL_BD82X6X && DEFAULT_CONSOLE_LOGLEVEL_8 # Only visible with the right southbridge and loglevel. config DEBUG_INTEL_ME diff --git a/src/drivers/ipmi/ipmi_kcs.c b/src/drivers/ipmi/ipmi_kcs.c index d3916198a6..60766215a0 100644 --- a/src/drivers/ipmi/ipmi_kcs.c +++ b/src/drivers/ipmi/ipmi_kcs.c @@ -41,7 +41,8 @@ static unsigned char ipmi_kcs_status(int port) { unsigned char status = inb(IPMI_STAT(port)); - printk(BIOS_SPEW, "%s: 0x%02x\n", __func__, status); + if (CONFIG(DEBUG_IPMI)) + printk(BIOS_SPEW, "%s: 0x%02x\n", __func__, status); return status; } @@ -75,7 +76,8 @@ static int ipmi_kcs_send_data_byte(int port, const unsigned char byte) { unsigned char status; - printk(BIOS_SPEW, "%s: 0x%02x\n", __func__, byte); + if (CONFIG(DEBUG_IPMI)) + printk(BIOS_SPEW, "%s: 0x%02x\n", __func__, byte); outb(byte, IPMI_DATA(port)); @@ -98,7 +100,8 @@ static int ipmi_kcs_send_last_data_byte(int port, const unsigned char byte) { unsigned char status; - printk(BIOS_SPEW, "%s: 0x%02x\n", __func__, byte); + if (CONFIG(DEBUG_IPMI)) + printk(BIOS_SPEW, "%s: 0x%02x\n", __func__, byte); if (wait_ibf_timeout(port)) return 1; @@ -119,7 +122,8 @@ static int ipmi_kcs_send_last_data_byte(int port, const unsigned char byte) static int ipmi_kcs_send_cmd_byte(int port, const unsigned char byte) { - printk(BIOS_SPEW, "%s: 0x%02x\n", __func__, byte); + if (CONFIG(DEBUG_IPMI)) + printk(BIOS_SPEW, "%s: 0x%02x\n", __func__, byte); if (wait_ibf_timeout(port)) return 1; From 44b614aef53ce6868e0e62f26a6f64b11ac5929a Mon Sep 17 00:00:00 2001 From: Marc Jones Date: Mon, 24 May 2021 12:12:47 -0600 Subject: [PATCH 49/67] mainboard/ocp/monolake: Fix up Kconfig to match devicetree.cb Remove the Gbe option and enable EHCI1 to match devicetree.cb. Change-Id: I122175aec313da0800f94da8b2cdf20cc498824f Signed-off-by: Marc Jones Reviewed-on: https://review.coreboot.org/c/coreboot/+/54882 Reviewed-by: Stefan Reinauer Reviewed-by: Angel Pons Tested-by: build bot (Jenkins) --- src/mainboard/ocp/monolake/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mainboard/ocp/monolake/Kconfig b/src/mainboard/ocp/monolake/Kconfig index bbc29a334f..668ef61c00 100644 --- a/src/mainboard/ocp/monolake/Kconfig +++ b/src/mainboard/ocp/monolake/Kconfig @@ -9,7 +9,7 @@ config BOARD_SPECIFIC_OPTIONS select INTEGRATED_UART if FSP_PACKAGE_DEFAULT select HAVE_FSP_BIN if FSP_PACKAGE_DEFAULT select SERIRQ_CONTINUOUS_MODE - select MAINBOARD_USES_IFD_GBE_REGION + select FSP_EHCI1_ENABLE select MAINBOARD_HAS_LPC_TPM select MAINBOARD_HAS_TPM1 select IPMI_KCS From 30bc0a4b66151d461fc07eee4fe749fbb5aea1aa Mon Sep 17 00:00:00 2001 From: Eugene Myers Date: Thu, 13 May 2021 06:03:28 -0400 Subject: [PATCH 50/67] arch/x86/include/arch: Add SMM_TASK_STATE_SEG This define is used to set up the STM SMM Descriptor table tr entry. Original-Signed-off-by: Eugene D. Myers Original-Change-Id: Iddb1f45444d03465a66a4ebb9fde5f206dc5b300 Original-Reviewed-on: https://review.coreboot.org/c/coreboot/+/38657 Original-Tested-by: build bot (Jenkins) Original-Reviewed-by: ron minnich Change-Id: I13a237c1372b79756e19d7ecbbd1946a44f2049f Signed-off-by: Eugene Myers Reviewed-on: https://review.coreboot.org/c/coreboot/+/55620 Tested-by: build bot (Jenkins) Reviewed-by: Patrick Georgi --- src/arch/x86/include/arch/rom_segs.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/arch/x86/include/arch/rom_segs.h b/src/arch/x86/include/arch/rom_segs.h index a19d3de461..c11def6b02 100644 --- a/src/arch/x86/include/arch/rom_segs.h +++ b/src/arch/x86/include/arch/rom_segs.h @@ -18,4 +18,11 @@ #define ROM_DATA_SEG 0x10 #define ROM_CODE_SEG64 0x18 +/* + * This define is placed here to make sure future romstage programmers + * know about it. + * It is used for STM setup code. + */ +#define SMM_TASK_STATE_SEG 0x20 + #endif /* ROM_SEGS_H */ From 4b776b705ff8bc8bcd8091e79851cf5fabbe8fb9 Mon Sep 17 00:00:00 2001 From: Elyes HAOUAS Date: Sat, 21 Dec 2019 07:24:22 +0100 Subject: [PATCH 51/67] drivers/ipmi/ipmi_fru: Add missing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit malloc() needs Original-Change-Id: I0cf6a5b76543cb6dac584de6628cfc459d5a60a8 Original-Signed-off-by: Elyes HAOUAS Original-Reviewed-on: https://review.coreboot.org/c/coreboot/+/37884 Original-Reviewed-by: Kyösti Mälkki Original-Tested-by: build bot (Jenkins) (cherry picked from commit f07d7dc2fdd71b3f8b5fd9cbde57068a98a9e602) Change-Id: I7febb9695199896e3f918b331e0b073d664883e9 Signed-off-by: Marc Jones Reviewed-on: https://review.coreboot.org/c/coreboot/+/55767 Tested-by: build bot (Jenkins) Reviewed-by: Martin Roth Reviewed-by: Jay Talbott --- src/drivers/ipmi/ipmi_fru.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/drivers/ipmi/ipmi_fru.c b/src/drivers/ipmi/ipmi_fru.c index a5e6ea60d5..8be53f8e0a 100644 --- a/src/drivers/ipmi/ipmi_fru.c +++ b/src/drivers/ipmi/ipmi_fru.c @@ -17,6 +17,8 @@ #include #include #include +#include + #include "ipmi_ops.h" #define MAX_FRU_BUSY_RETRY 5 From e7a126fbc276df57dc1d05c4a40a259f2e5d06d7 Mon Sep 17 00:00:00 2001 From: Jacob Garber Date: Sat, 7 Mar 2020 14:55:35 -0700 Subject: [PATCH 52/67] drivers/ipmi: Fix buffer double-free If reading the data for the asset_tag fails, that buffer should be freed, not the one for serial_number. Original-Change-Id: I2ecaf7fd0f23f2fb5a6aa0961c7e17fff04847f4 Original-Signed-off-by: Jacob Garber Original-Found-by: Coverity CID 1419481, 1419485 Original-Reviewed-on: https://review.coreboot.org/c/coreboot/+/39378 Original-Tested-by: build bot (Jenkins) Original-Reviewed-by: Paul Menzel Original-Reviewed-by: Patrick Rudolph Original-Reviewed-by: Angel Pons (cherry picked from commit f8cd291344f2a8b8ecc90cfb7bb5ca864dcc9441) Change-Id: I4947ba4578b5a41a30e487f5572412cb6ed79a1b Signed-off-by: Marc Jones Reviewed-on: https://review.coreboot.org/c/coreboot/+/55768 Reviewed-by: Martin Roth Reviewed-by: Jay Talbott Tested-by: build bot (Jenkins) --- src/drivers/ipmi/ipmi_fru.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/drivers/ipmi/ipmi_fru.c b/src/drivers/ipmi/ipmi_fru.c index 8be53f8e0a..43ee6b3a35 100644 --- a/src/drivers/ipmi/ipmi_fru.c +++ b/src/drivers/ipmi/ipmi_fru.c @@ -319,7 +319,7 @@ static void read_fru_product_info_area(const int port, const uint8_t id, goto out; } if (!data2str((const uint8_t *)data_ptr, info->asset_tag, length)) - free(info->serial_number); + free(info->asset_tag); } out: From 2953527a677214637696a4bfe8298049b78ac09b Mon Sep 17 00:00:00 2001 From: Johnny Lin Date: Fri, 4 Sep 2020 17:05:58 +0800 Subject: [PATCH 53/67] drivers/ipmi: Add CONFIG_IPMI_KCS_TIMEOUT_MS for IPMI KCS timeout value With the current timeout of 1000 cycles of 100 microsecond would see timeout occurs on OCP Delta Lake if the log level is set to values smaller than 8. Because the prink(BIOS_SPEW, ..) in ipmi_kcs_status() creates delay and avoid the problem, but after setting the log level to 4 we see some timeout occurs. The unit is millisecond and the default value is set to 5000 according to IPMI spec v2.0 rev 1.1 Sec. 9.15, a five-second timeout or greater is recommended. Tested=On OCP Delta Lake, with log level 4 cannot observe timeout occurs. Original-Change-Id: I42ede1d9200bb5d0dbb455d2ff66e2816f10e86b Original-Signed-off-by: Johnny Lin Original-Reviewed-on: https://review.coreboot.org/c/coreboot/+/45103 Original-Reviewed-by: Patrick Georgi Original-Reviewed-by: Angel Pons Original-Reviewed-by: Paul Menzel Original-Tested-by: build bot (Jenkins) (cherry picked from commit d04c06b472495bce49af0e171c333de26e8fd86a) Change-Id: I7046467d41e1feddb07081964466c8189321cb1d Signed-off-by: Marc Jones Reviewed-on: https://review.coreboot.org/c/coreboot/+/55769 Reviewed-by: Martin Roth Reviewed-by: Jay Talbott Tested-by: build bot (Jenkins) --- src/drivers/ipmi/Kconfig | 9 +++++++++ src/drivers/ipmi/ipmi_kcs.c | 31 +++++++++++++------------------ 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/drivers/ipmi/Kconfig b/src/drivers/ipmi/Kconfig index 37cfc0d230..b54b23d677 100644 --- a/src/drivers/ipmi/Kconfig +++ b/src/drivers/ipmi/Kconfig @@ -18,3 +18,12 @@ config IPMI_FRU_SINGLE_RW_SZ IPMB messages are limited to 32-bytes total. When the data size is larger than this value, IPMI can complete reading/writing the data over multiple commands. + +config IPMI_KCS_TIMEOUT_MS + int + default 5000 + depends on IPMI_KCS + help + The time unit is millisecond for each IPMI KCS transfer. + IPMI spec v2.0 rev 1.1 Sec. 9.15, a five-second timeout or + greater is recommended. diff --git a/src/drivers/ipmi/ipmi_kcs.c b/src/drivers/ipmi/ipmi_kcs.c index 60766215a0..bf7f39384e 100644 --- a/src/drivers/ipmi/ipmi_kcs.c +++ b/src/drivers/ipmi/ipmi_kcs.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include "ipmi_kcs.h" #define IPMI_KCS_STATE(_x) ((_x) >> 6) @@ -48,27 +48,22 @@ static unsigned char ipmi_kcs_status(int port) static int wait_ibf_timeout(int port) { - int timeout = 1000; - do { - if (!(ipmi_kcs_status(port) & IPMI_KCS_IBF)) - return 0; - udelay(100); - } while (timeout--); - printk(BIOS_ERR, "wait_ibf timeout!\n"); - return timeout; + if (!wait_ms(CONFIG_IPMI_KCS_TIMEOUT_MS, !(ipmi_kcs_status(port) & IPMI_KCS_IBF))) { + printk(BIOS_ERR, "wait_ibf timeout!\n"); + return 1; + } else { + return 0; + } } static int wait_obf_timeout(int port) { - int timeout = 1000; - do { - if ((ipmi_kcs_status(port) & IPMI_KCS_OBF)) - return 0; - udelay(100); - } while (timeout--); - - printk(BIOS_ERR, "wait_obf timeout!\n"); - return timeout; + if (!wait_ms(CONFIG_IPMI_KCS_TIMEOUT_MS, (ipmi_kcs_status(port) & IPMI_KCS_OBF))) { + printk(BIOS_ERR, "wait_obf timeout!\n"); + return 1; + } else { + return 0; + } } From 40dccd9f36ba6e3c7014f28634cfb9f7d29a043b Mon Sep 17 00:00:00 2001 From: Marc Jones Date: Tue, 22 Jun 2021 14:05:41 -0600 Subject: [PATCH 54/67] mainboard/ocp/monolake: Give the BMC time to startup Set bmc_boot_timeout and wait_for_bmc to give the BMC more time to respond before coreboot times out and moves on. Passes IPMI BMC selftest. Change-Id: I310a08b8c134cf839381675ade2fe7deee9b1909 Signed-off-by: Marc Jones Reviewed-on: https://review.coreboot.org/c/coreboot/+/55770 Reviewed-by: Martin Roth Reviewed-by: Jay Talbott Tested-by: build bot (Jenkins) --- src/mainboard/ocp/monolake/devicetree.cb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mainboard/ocp/monolake/devicetree.cb b/src/mainboard/ocp/monolake/devicetree.cb index 0e3857b1de..4f351b0c4c 100644 --- a/src/mainboard/ocp/monolake/devicetree.cb +++ b/src/mainboard/ocp/monolake/devicetree.cb @@ -14,6 +14,9 @@ chip soc/intel/fsp_broadwell_de chip drivers/ipmi # BMC KCS device pnp ca2.0 on end register "bmc_i2c_address" = "0x20" + # On cold boot it takes a while for the BMC to start the IPMI service + register "wait_for_bmc" = "1" + register "bmc_boot_timeout" = "60" end end # LPC Bridge device pci 1f.2 on end # SATA Controller From 440149804123c4c99041f100f0ae103103de71d1 Mon Sep 17 00:00:00 2001 From: Marc Jones Date: Fri, 10 Sep 2021 12:04:50 -0600 Subject: [PATCH 55/67] Documentation: Add OCP Mono Lake mainboard Add information about the OCP Mono Lake mainboard. Change-Id: I2109cca0e4037a2945bcb7e4d80897b48ada54af Signed-off-by: Marc Jones Reviewed-on: https://review.coreboot.org/c/coreboot/+/57561 Reviewed-by: Stefan Reinauer Reviewed-by: Jay Talbott Tested-by: Stefan Reinauer Tested-by: build bot (Jenkins) --- Documentation/mainboard/index.md | 4 + Documentation/mainboard/ocp/monolake.md | 146 ++++++++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 Documentation/mainboard/ocp/monolake.md diff --git a/Documentation/mainboard/index.md b/Documentation/mainboard/index.md index 60302cbe0f..39cd9a4d9d 100644 --- a/Documentation/mainboard/index.md +++ b/Documentation/mainboard/index.md @@ -99,6 +99,10 @@ The boards in this section are not real mainboards, but emulators. - [MS-7707](msi/ms7707/ms7707.md) +## OCP + +- [Mono Lake](ocp/monolake.md) + ## Open Cellular - [Elgon](opencellular/elgon.md) diff --git a/Documentation/mainboard/ocp/monolake.md b/Documentation/mainboard/ocp/monolake.md new file mode 100644 index 0000000000..e825bfff7b --- /dev/null +++ b/Documentation/mainboard/ocp/monolake.md @@ -0,0 +1,146 @@ +# OCP Mono Lake + +This page describes coreboot support status for the [OCP] (Open Compute Project) +Mono Lake server platform. + +## Introduction + +OCP Mono Lake server platform is a component of multi-host server Yosemite-V1. +Facebook [introduced Yosemite] in 2015 and the [Mono Lake was accepted] to OCP in 2019. + +Mono Lake server is a single socket BroadwellDE server. + +Yosemite-V1 may host up to 4 Mono Lake servers (blades) in one sled. + +The Yosemite-V1 system is in mass production. Facebook, Intel, ITRenew and partners +jointly develop Open System Firmware (OSF) solution on Mono Lake as an alternative +solution. The OSF solution is based on coreboot/FSP/LinuxBoot stack. A firmware binary +is available from ITRenew. + +coreboot Mono Lake is supported on the coreboot version 4.11 branch. +The Broadwell-DE FSP v1.0 support was dropped after 4.11. + + +## Required blobs + +Mono Lake server OSF solution requires: +- [FSP] blob: SysPro custom FSP is required to support the 16-core Broadwell-DE on Mono Lake +- Microcode: Available through github.com:otcshare/Intel-Generic-Microcode.git +- ME binary: Available under NDA with Intel + +## Payload +- LinuxBoot: Linuxboot is the prefered coreboot payload for Mono Lake. + It can be built following [All about u-root]. + + Tested configuration: + Linux Kernel v5.10.44 + [u-root Mono Lake pull request] + u-root build command: + GO111MODULE=off u-root -build=bb -uinitcmd=systemboot \ + -files="${FLASHROMDIR}/flashrom:bin/flashrom" \ + -files="${VPDDIR}/vpd:bin/vpd" \ + core github.com/u-root/u-root/cmds/boot/{systemboot,pxeboot,boot} \ + github.com/u-root/u-root/cmds/exp/{cbmem,dmidecode,modprobe,ipmidump,netbootxyz} \ + + note: flashrom and vpd binaries must be precompiled + +## Flashing coreboot + +Mono Lake in-band BIOS firmware image update uses [flashrom]: + flashrom -p internal:ich_spi_mode=hwseq -c "Opaque flash chip" --ifd \ + -i bios --noverify-all -w + +Yosemite-V1 OpenBMC BIOS firmware image update uses fw-util: + fw-util slotx --update bios + +## Yosimite-V1 server controls + +To power off/on a Mono Lake host: + power-util slotx off + power-util slotx on + +To connect to coreboot and Linux console through SOL (Serial Over Lan): + sol-util slotx + +## Firmware configurations +[ChromeOS VPD] is used to store most of the firmware configurations. +RO_VPD region holds default values, while RW_VPD region holds customized +values. + +VPD variables supported are: +- firmware_version: This variable holds overall firmware version. coreboot + uses that value to populate smbios type 1 version field. +- bmc_bootorder_override: When it's set to 1 IPMI OEM command can override boot + order. The boot order override is done in the u-root LinuxBoot payload. +- systemboot_log_level: u-root package systemboot log levels, would be mapped to + quiet/verbose in systemboot as that is all we have for now. 5 to 8 would be + mapped to verbose, 0 to 4 and 9 would be mapped to quiet. +- VPDs affecting coreboot are in src/mainboard/ocp/monolake/mainboard.c. + No coreboot VPD are required, uses safe defaults. + +## Working features +The solution is developed using LinuxBoot payload with Linux kernel 5.2.9, +and [u-root] as initramfs. +- BMC integration: + - BMC readiness check + - IPMI commands + - watchdog timer + - POST complete pin acknowledgement + - Check BMC version: ipmidump -device +- Early serial output +- ACPI tables: DMAR/DSDT/FACP/FACS/HPET/MCFG/SPMI/SRAT/SLIT/SSDT/XSDT +- FSP MRC cache support (Skipping memory training upon subsequent reboots) +- Versions + - Check FSP version: cbmem | grep LB_TAG_PLATFORM_BLOB_VERSION + - Check Microcode version: cat /proc/cpuinfo | grep microcode +- Devices: + - Boot drive + - All 5 data drives + - NIC card +- SMBIOS: + - Type 0 – BIOS Information + - Type 1 – System Information + - Type 2 – Baseboard Information + - Type 3 – System Enclosure or Chassis + - Type 4 – Processor Information + - Type 7 – Cache Information + - Type 16 – Physical Memory Array + - Type 17 – Memory Device + - Type 32 – System Boot Information + - Type 38 – IPMI Device Information + - Type 41 – Onboard Devices Extended Information + - Type 127 – End-of-Table +- Power button +- u-root boot +- u-root pxeboot + +## Stress and Performance tests passed + +## Known issues + +### Feature gaps +- flashrom command not able to update ME region +- ACPI BERT table +- PCIe hotplug through VPP (Virtual Pin Ports) +- RO_VPD region as well as other RO regions are not write protected +- Not able to selectively enable/disable core + +## Technology + +```eval_rst ++------------------------+---------------------------------------------+ +| Processor (1 socket) | Broadwell-DE | ++------------------------+---------------------------------------------+ +| BMC | Aspeed AST 1250 | ++------------------------+---------------------------------------------+ +``` + +[OCP]: https://www.opencompute.org +[introduced Yosemite]: https://engineering.fb.com/2015/03/10/core-data/introducing-yosemite-the-first-open-source-modular-chassis-for-high-powered-microservers/ +[Mono Lake was accepted]: https://www.opencompute.org/contributions?query=Tioga%20Pass%20v1.0 +[FSP]: https://doc.coreboot.org/soc/intel/fsp/index.html +[u-root Mono Lake pull request]: https://github.com/u-root/u-root/pull/2045 +[flashrom]: https://flashrom.org/Flashrom +[All about u-root]: https://github.com/linuxboot/book/tree/master/u-root +[u-root]: https://u-root.org/ +[ChromeOS VPD]: https://chromium.googlesource.com/chromiumos/platform/vpd/+/master/README.md From 6ffb50080a2978cbffe952bee4b6c6b7877c4224 Mon Sep 17 00:00:00 2001 From: Iru Cai Date: Wed, 21 Jul 2021 23:14:35 +0800 Subject: [PATCH 56/67] Makefile.inc: Replace linker flag -nostartfiles with --nmagic While the gcc(1) driver has the `-nostartfiles` option, ld(1), the program the coreboot toolchain uses to link the object files, doesn't have it. In binutils before 2.36, this option is interpreted as `-n -o startfiles`, in which the `-o` option is overridden by a later `-o` option, so only the `-n` option has effect, which is the `--nmagic` long option of ld(1). So the correct linker option in this place is `--nmagic`. It is tested that without `--nmagic`, ld can generate a much bigger x86_64 romstage, so this option is still needed. This error is found when trying to update binutils to 2.36 and later versions, where ld(1) is unable to disambiguate options and reports an error. Change-Id: I27dc2209abdc6fec866716a252736c5cf236a347 Signed-off-by: Iru Cai Reviewed-on: https://review.coreboot.org/c/coreboot/+/56490 Tested-by: build bot (Jenkins) Reviewed-by: Martin Roth Signed-off-by: Uwe Poeche Reviewed-on: https://review.coreboot.org/c/coreboot/+/61958 Reviewed-by: Werner Zeh Reviewed-by: Elyes Haouas --- Makefile.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.inc b/Makefile.inc index 0b09472d39..be198d6580 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -478,7 +478,7 @@ ADAFLAGS_common += -gnatwa.eeD.HHTU.U.W.Y # Disable style checks for now ADAFLAGS_common += -gnatyN -LDFLAGS_common := --gc-sections -nostdlib -nostartfiles -static --emit-relocs +LDFLAGS_common := --gc-sections -nostdlib --nmagic -static --emit-relocs ifeq ($(CONFIG_WARNINGS_ARE_ERRORS),y) CFLAGS_common += -Werror From 60004e276ab0a5845f0652c7d8dd40ed7c5ab1b9 Mon Sep 17 00:00:00 2001 From: Eugene Myers Date: Wed, 16 Jun 2021 07:55:58 -0400 Subject: [PATCH 57/67] soc/intel: Add get_pmbase Originally a part of security/intel/stm. Add get_pmbase to the intel platform setup code. get_pmbase is used by the coreboot STM setup functions to ensure that the pmbase is accessable by the SMI handler during runtime. The pmbase has to be accounted for in the BIOS resource list so that the SMI handler is allowed this access. Original-Change-Id: If6f6295c5eba9eb20e57ab56e7f965c8879e93d2 Original-Signed-off-by: Eugene D. Myers Original-Reviewed-on: https://review.coreboot.org/c/coreboot/+/37990 Original-Reviewed-by: Patrick Georgi Original-Tested-by: build bot (Jenkins) Change-Id: I7f9ef32946a17aa0bbcbc375bc34b48e62620694 Signed-off-by: Eugene Myers Reviewed-on: https://review.coreboot.org/c/coreboot/+/55621 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer --- src/soc/intel/apollolake/include/soc/pm.h | 3 ++ src/soc/intel/apollolake/pmutil.c | 6 ++++ src/soc/intel/broadwell/include/soc/pm.h | 3 ++ src/soc/intel/broadwell/pmutil.c | 6 ++++ src/soc/intel/cannonlake/include/soc/pm.h | 3 ++ src/soc/intel/cannonlake/pmutil.c | 6 ++++ .../intel/fsp_broadwell_de/include/soc/pm.h | 28 +++++++++++++++++++ src/soc/intel/icelake/include/soc/pm.h | 3 ++ src/soc/intel/icelake/pmutil.c | 6 ++++ src/soc/intel/quark/acpi.c | 7 +++++ src/soc/intel/quark/include/soc/pm.h | 3 ++ src/soc/intel/skylake/include/soc/pm.h | 3 ++ src/soc/intel/skylake/pmutil.c | 6 ++++ src/soc/intel/tigerlake/include/soc/pm.h | 2 ++ src/soc/intel/tigerlake/pmutil.c | 6 ++++ 15 files changed, 91 insertions(+) create mode 100644 src/soc/intel/fsp_broadwell_de/include/soc/pm.h diff --git a/src/soc/intel/apollolake/include/soc/pm.h b/src/soc/intel/apollolake/include/soc/pm.h index d0b0421561..22e414c803 100644 --- a/src/soc/intel/apollolake/include/soc/pm.h +++ b/src/soc/intel/apollolake/include/soc/pm.h @@ -250,4 +250,7 @@ void pch_log_state(void); void enable_pm_timer_emulation(void); +/* STM Support */ +uint16_t get_pmbase(void); + #endif diff --git a/src/soc/intel/apollolake/pmutil.c b/src/soc/intel/apollolake/pmutil.c index 559adad405..8151afc08d 100644 --- a/src/soc/intel/apollolake/pmutil.c +++ b/src/soc/intel/apollolake/pmutil.c @@ -246,3 +246,9 @@ int vbnv_cmos_failed(void) return rtc_failure; } + +/* STM Support */ +uint16_t get_pmbase(void) +{ + return (uint16_t) ACPI_BASE_ADDRESS; +} diff --git a/src/soc/intel/broadwell/include/soc/pm.h b/src/soc/intel/broadwell/include/soc/pm.h index 18004fa77d..c9074d8a0b 100644 --- a/src/soc/intel/broadwell/include/soc/pm.h +++ b/src/soc/intel/broadwell/include/soc/pm.h @@ -155,4 +155,7 @@ void disable_gpe(uint32_t mask); /* Return the selected ACPI SCI IRQ */ int acpi_sci_irq(void); +/* STM Support */ +uint16_t get_pmbase(void); + #endif diff --git a/src/soc/intel/broadwell/pmutil.c b/src/soc/intel/broadwell/pmutil.c index 00db6156ec..2445dfacf6 100644 --- a/src/soc/intel/broadwell/pmutil.c +++ b/src/soc/intel/broadwell/pmutil.c @@ -458,3 +458,9 @@ int vboot_platform_is_resuming(void) return acpi_sleep_from_pm1(inl(ACPI_BASE_ADDRESS + PM1_CNT)) == ACPI_S3; } + +/* STM Support */ +uint16_t get_pmbase(void) +{ + return (uint16_t) ACPI_BASE_ADDRESS; +} diff --git a/src/soc/intel/cannonlake/include/soc/pm.h b/src/soc/intel/cannonlake/include/soc/pm.h index 5b85e74bf5..356f0bcc6f 100644 --- a/src/soc/intel/cannonlake/include/soc/pm.h +++ b/src/soc/intel/cannonlake/include/soc/pm.h @@ -172,5 +172,8 @@ void pmc_set_disb(void); /* Clear PMCON status bits */ void pmc_clear_pmcon_sts(void); +/* STM Support */ +uint16_t get_pmbase(void); + #endif /* !defined(__ACPI__) */ #endif diff --git a/src/soc/intel/cannonlake/pmutil.c b/src/soc/intel/cannonlake/pmutil.c index 428a89fe4b..5774873180 100644 --- a/src/soc/intel/cannonlake/pmutil.c +++ b/src/soc/intel/cannonlake/pmutil.c @@ -273,3 +273,9 @@ void soc_fill_power_state(struct chipset_power_state *ps) printk(BIOS_DEBUG, "GBLRST_CAUSE: %08x %08x\n", ps->gblrst_cause[0], ps->gblrst_cause[1]); } + +/* STM Support */ +uint16_t get_pmbase(void) +{ + return (uint16_t) ACPI_BASE_ADDRESS; +} diff --git a/src/soc/intel/fsp_broadwell_de/include/soc/pm.h b/src/soc/intel/fsp_broadwell_de/include/soc/pm.h new file mode 100644 index 0000000000..c1b6ee9e80 --- /dev/null +++ b/src/soc/intel/fsp_broadwell_de/include/soc/pm.h @@ -0,0 +1,28 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * Copyright (C) 2013 Google Inc. + * Copyright (C) 2015-2016 Intel Corp. + * Copyright (C) 2016-2018 Siemens AG + * + * 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. + */ + +#ifndef _SOC_FSP_BROADWELL_DE_PM_H_ +#define _SOC_FSP_BROADWELL_DE_PM_H_ + +/* + * Brings in get_pmbase so that StmPlatformResource.c can build + * under 4.11 + */ + +#include +#endif diff --git a/src/soc/intel/icelake/include/soc/pm.h b/src/soc/intel/icelake/include/soc/pm.h index 44888ec747..34c32a9ac2 100644 --- a/src/soc/intel/icelake/include/soc/pm.h +++ b/src/soc/intel/icelake/include/soc/pm.h @@ -171,5 +171,8 @@ void pmc_set_disb(void); /* Clear PMCON status bits */ void pmc_clear_pmcon_sts(void); +/* STM Support */ +uint16_t get_pmbase(void); + #endif /* !defined(__ACPI__) */ #endif diff --git a/src/soc/intel/icelake/pmutil.c b/src/soc/intel/icelake/pmutil.c index 8efd426606..a4971da984 100644 --- a/src/soc/intel/icelake/pmutil.c +++ b/src/soc/intel/icelake/pmutil.c @@ -272,3 +272,9 @@ void soc_fill_power_state(struct chipset_power_state *ps) printk(BIOS_DEBUG, "GBLRST_CAUSE: %08x %08x\n", ps->gblrst_cause[0], ps->gblrst_cause[1]); } + +/* STM Support */ +uint16_t get_pmbase(void) +{ + return (uint16_t) ACPI_BASE_ADDRESS; +} diff --git a/src/soc/intel/quark/acpi.c b/src/soc/intel/quark/acpi.c index ffcd91f13d..5006b19d47 100644 --- a/src/soc/intel/quark/acpi.c +++ b/src/soc/intel/quark/acpi.c @@ -104,3 +104,10 @@ void acpi_fill_in_fadt(acpi_fadt_t *fadt) printk(BIOS_SPEW, " 0x%08x: RESET\n", fadt->reset_reg.addrl); } + +uint16_t get_pmbase(void) +{ + struct device *dev = pcidev_on_root(PCI_DEVICE_NUMBER_QNC_LPC, + PCI_FUNCTION_NUMBER_QNC_LPC); + return (uint16_t) pci_read_config32(dev, R_QNC_LPC_PM1BLK) & B_QNC_LPC_PM1BLK_MASK; +} diff --git a/src/soc/intel/quark/include/soc/pm.h b/src/soc/intel/quark/include/soc/pm.h index a3fb02f7db..e02b8a274e 100644 --- a/src/soc/intel/quark/include/soc/pm.h +++ b/src/soc/intel/quark/include/soc/pm.h @@ -27,4 +27,7 @@ struct chipset_power_state { struct chipset_power_state *get_power_state(void); int fill_power_state(void); +/* STM Support */ +uint16_t get_pmbase(void); + #endif /* _SOC_PM_H_ */ diff --git a/src/soc/intel/skylake/include/soc/pm.h b/src/soc/intel/skylake/include/soc/pm.h index 18b0c15d64..007d29cadc 100644 --- a/src/soc/intel/skylake/include/soc/pm.h +++ b/src/soc/intel/skylake/include/soc/pm.h @@ -197,4 +197,7 @@ static inline int deep_s5_enabled(void) return !!(deep_s5_pol & (S5DC_GATE_SUS | S5AC_GATE_SUS)); } +/* STM Support */ +uint16_t get_pmbase(void); + #endif diff --git a/src/soc/intel/skylake/pmutil.c b/src/soc/intel/skylake/pmutil.c index 329cea9621..aac5d1d939 100644 --- a/src/soc/intel/skylake/pmutil.c +++ b/src/soc/intel/skylake/pmutil.c @@ -266,3 +266,9 @@ void soc_fill_power_state(struct chipset_power_state *ps) printk(BIOS_DEBUG, "GBLRST_CAUSE: %08x %08x\n", ps->gblrst_cause[0], ps->gblrst_cause[1]); } + +/* STM Support */ +uint16_t get_pmbase(void) +{ + return ACPI_BASE_ADDRESS; +} diff --git a/src/soc/intel/tigerlake/include/soc/pm.h b/src/soc/intel/tigerlake/include/soc/pm.h index fb9b67bc23..d2f47e271b 100644 --- a/src/soc/intel/tigerlake/include/soc/pm.h +++ b/src/soc/intel/tigerlake/include/soc/pm.h @@ -177,5 +177,7 @@ void pmc_set_disb(void); /* Clear PMCON status bits */ void pmc_clear_pmcon_sts(void); +/* STM Support */ +uint16_t get_pmbase(void); #endif /* !defined(__ACPI__) */ #endif diff --git a/src/soc/intel/tigerlake/pmutil.c b/src/soc/intel/tigerlake/pmutil.c index 53f86097ee..39659c3c6f 100644 --- a/src/soc/intel/tigerlake/pmutil.c +++ b/src/soc/intel/tigerlake/pmutil.c @@ -274,3 +274,9 @@ void soc_fill_power_state(struct chipset_power_state *ps) printk(BIOS_DEBUG, "GBLRST_CAUSE: %08x %08x\n", ps->gblrst_cause[0], ps->gblrst_cause[1]); } + +/* STM Support */ +uint16_t get_pmbase(void) +{ + return (uint16_t) ACPI_BASE_ADDRESS; +} From 2b32db6ddc0f9382466f26ad71c190b63cb8e2b7 Mon Sep 17 00:00:00 2001 From: Eugene Myers Date: Wed, 16 Jun 2021 09:06:00 -0400 Subject: [PATCH 58/67] security/intel/stm: Add options for STM build This patch adds options that support building the STM as a part of the coreboot build. The option defaults assume that these configuration options are set as follows: IED_REGION_SIZE = 0x400000 SMM_RESERVED_SIZE = 0x200000 SMM_TSEG_SIZE = 0x800000 Original-Change-Id: I80ed7cbcb93468c5ff93d089d77742ce7b671a37 Original-Signed-off-by: Eugene Myers Original-Reviewed-on: https://review.coreboot.org/c/coreboot/+/44686 Original-Tested-by: build bot (Jenkins) Original-Reviewed-by: ron minnich Change-Id: I982cde1299c87b5cf4f495905b53a6c107842956 Signed-off-by: Eugene Myers Reviewed-on: https://review.coreboot.org/c/coreboot/+/55622 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer --- src/security/intel/stm/Kconfig | 87 ++++++++++++++++++++++++++--- src/security/intel/stm/Makefile | 33 +++++++++++ src/security/intel/stm/Makefile.inc | 10 ++++ 3 files changed, 123 insertions(+), 7 deletions(-) create mode 100644 src/security/intel/stm/Makefile diff --git a/src/security/intel/stm/Kconfig b/src/security/intel/stm/Kconfig index a74eba8522..3098d5c901 100644 --- a/src/security/intel/stm/Kconfig +++ b/src/security/intel/stm/Kconfig @@ -29,20 +29,93 @@ menu "SMI Transfer Monitor (STM)" config MSEG_SIZE hex "mseg size" - default 0x400000 + default 0x100000 help - STM only - 0x100000 - STM/PE - 0x300000+ depending on the amount of memory needed - for the protected execution virtual - machine (VM/PE) + The MSEG_SIZE of 0x100000 assumes that: + IED_REGION_SIZE = 0x400000 + SMM_RESERVED_SIZE = 0x200000 + SMM_TSEG_SIZE = 0x800000 + + To use STM/PE, a larger MSEG_SIZE is necessary. This can be + done by either increasing SMM_TSEG_SIZE or reducing the + IED_REGION_SIZE and/or SMM_RESERVED_SIZE or some combination + of the three. + NOTE: The authors experience is that these configuration + parameters have to be changed at the soc Konfig for them to + be applied. + Minimum sizes: + STM only - 0x100000 - Supports up to 38 processor threads + - 0x200000 - Supports up to 102 processor threads + STM/PE - 0x300000+ depending on the amount of memory needed + for the protected execution virtual + machine (VM/PE) + +config STM_STMPE_ENABLED + bool "STM/PE Enabled" + default n + help + STM/PE provides for additional virtual machines in SMRAM + that provides a protected execution environment for + applications such as introspection, which need to be + protected from malicious code. More information can be + found on the stmpe branch of + https://review.coreboot.org/STM + config BIOS_RESOURCE_LIST_SIZE - hex "bios_resource_list_size" + hex "bios resource list size" default 0x1000 + help + The BIOS resource list defines the resources that the + SMI handler needs. This list is created during the + coreboot bootup. Unless there has been a lot of elements + added to this list, this value should not change. config STM_BINARY_FILE string "STM binary file" - default "3rdparty/blobs/cpu/intel/stm/stm.bin" + default "3rdparty/stm/Stm/build/StmPkg/Core/stm.bin" + help + Location of the STM binary file. The default location is + where the file will be located when coreboot builds + the STM. + +config STM_HEAPSIZE + hex "stm heapsize" + default 0x46000 + help + The STM_HEAPSIZE defines the heap space that is available + to the STM. The default size assumes a MSEG_SIZE of 0x100000. + For STM/PE this size should be a minimum of 0x246000. + +config STM_TTYS0_BASE + hex "stm uart" + default TTYS0_BASE if TTYS0_BASE + default 0x000 + help + Defines the serial port for STM console output. 0x000 indicates + no serial port. + +config STM_CBMEM_CONSOLE + bool "STM cbmem console" + default n + depends on CONSOLE_CBMEM + help + Places the STM console output into the cbmem. + +choice + prompt "Select STM console output" + +config STM_CONSOLE_DEBUG + bool "Debug output" + depends on STM_CBMEM_CONSOLE || STM_TTYS0_BASE + help + "Produces all STM console output" + +config STM_CONSOLE_RELEASE + bool "Deactivate console output" + help + "No console output is produced" +endchoice endmenu #STM diff --git a/src/security/intel/stm/Makefile b/src/security/intel/stm/Makefile new file mode 100644 index 0000000000..1493869e80 --- /dev/null +++ b/src/security/intel/stm/Makefile @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: BSD-2-Clause + +project_name=STM +project_dir=../../../../3rdparty/stm/ +build_dir=$(project_dir)/Stm/build +project_git_branch=$(CONFIG_STM_GIT_BRANCH) + +ifeq ($(CONFIG_STM_CONSOLE_DEBUG),y) +STM_BUILD="debug" +endif + +ifeq ($(CONFIG_STM_CONSOLE_RELEASE),y) +STM_BUILD="release" +endif + + +all: build + +build: + echo "STM - Build" + cd $(project_dir)/Stm; \ + mkdir -p build; \ + cd build; \ + cmake .. -DBIOS=coreboot \ + -DUART=$(CONFIG_STM_TTYS0_BASE) \ + -DHEAPSIZE=$(CONFIG_STM_HEAPSIZE) \ + -DCBMEM_ENABLE=$(CONFIG_STM_CBMEM_CONSOLE) \ + -DSTMPE_ENABLED=$(CONFIG_STM_STMPE_ENABLED) \ + -DBUILD=$(STM_BUILD); \ + $(MAKE); + + +.PHONY: build diff --git a/src/security/intel/stm/Makefile.inc b/src/security/intel/stm/Makefile.inc index 1a23fe97f2..3f5b9ee5c6 100644 --- a/src/security/intel/stm/Makefile.inc +++ b/src/security/intel/stm/Makefile.inc @@ -8,3 +8,13 @@ stm.bin-type := raw ramstage-$(CONFIG_STM) += SmmStm.c ramstage-$(CONFIG_STM) += StmPlatformSmm.c ramstage-$(CONFIG_STM) += StmPlatformResource.c + +3rdparty/stm/Stm/build/StmPkg/Core/stm.bin: $(obj)/config.h + $(MAKE) -C src/security/intel/stm \ + CONFIG_STM_TTYSO_BASE=$(CONFIG_STM_TTYSO_BASE) \ + CONFIG_STM_HEAPSIZE=$(CONFIG_STM_HEAPSIZE) \ + CONFIG_STM_CONSOLE_DEBUG=$(CONFIG_STM_CONSOLE_DEBUG) \ + CONFIG_STM_CONSOLE_RELEASE=$(CONFIG_STM_CONSOLE_RELEASE) \ + CONFIG_STM_GIT_BRANCH=$(CONFIG_STM_GIT_BRANCH) \ + CONFIG_STM_STMPE_ENABLED=$(CONFIG_STM_STMPE_ENABLED) \ + CONFIG_STM_CBMEM_CONSOLE=$(CONFIG_STM_CBMEM_CONSOLE) From 701180f069b47f8d351b516d02225d0c00906319 Mon Sep 17 00:00:00 2001 From: Eugene Myers Date: Wed, 16 Jun 2021 09:26:38 -0400 Subject: [PATCH 59/67] security/intel/stm/SmmStm.c: Fix size_t printf format error Replaced the 'l' with a 'z' to clear up the issue. Change-Id: I696b615b4dd3bacda7151c91fff17f9b01b17821 Signed-off-by: Eugene Myers Reviewed-on: https://review.coreboot.org/c/coreboot/+/55623 Reviewed-by: Stefan Reinauer Tested-by: build bot (Jenkins) --- src/security/intel/stm/SmmStm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/security/intel/stm/SmmStm.c b/src/security/intel/stm/SmmStm.c index f23be70217..523a63f420 100644 --- a/src/security/intel/stm/SmmStm.c +++ b/src/security/intel/stm/SmmStm.c @@ -490,7 +490,7 @@ int add_pi_resource(STM_RSC *resource_list, uint32_t num_entries) return -1; // INVALID_PARAMETER; resource_size = get_resource_size(resource_list, num_entries); - printk(BIOS_DEBUG, "STM: ResourceSize - 0x%08lx\n", resource_size); + printk(BIOS_DEBUG, "STM: ResourceSize - 0x%08x\n", (int) resource_size); if (resource_size == 0) return -1; // INVALID_PARAMETER; From 75c35288d85783de0985eb71a9a428214f491be4 Mon Sep 17 00:00:00 2001 From: Eugene Myers Date: Tue, 30 Mar 2021 18:06:05 -0400 Subject: [PATCH 60/67] 3rdparty: Add STM as a submodule The patch incorporates the STM build as a part of the coreboot build. A separate patch lists and documents the options that the developer can use. In most cases the default options will suffice. Original-Change-Id: I8c6e0c85edd4e2b0658791553bd9947656e8c796 Original-Signed-off-by: Eugene D Myers Original-Reviewed-on: https://review.coreboot.org/c/coreboot/+/44687 Original-Tested-by: build bot (Jenkins) Original-Reviewed-by: ron minnich Change-Id: I901cb429d8050fb2a7c839e8ef29ac3359239d2c Signed-off-by: Eugene Myers Reviewed-on: https://review.coreboot.org/c/coreboot/+/55625 Reviewed-by: Stefan Reinauer Tested-by: build bot (Jenkins) --- .gitmodules | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitmodules b/.gitmodules index 1b47275290..14782d43c8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -43,3 +43,7 @@ url = ../amd_blobs update = none ignore = dirty +[submodule "3rdparty/stm"] + path = 3rdparty/stm + url = ../STM + branch = stmpe From 56ce49f10f085e531022c0cbafa024292ce810d5 Mon Sep 17 00:00:00 2001 From: Eugene Myers Date: Thu, 1 Apr 2021 13:37:49 -0400 Subject: [PATCH 61/67] soc/intel/fsp_broadwell_de: Enable STM for broadwell_de This patch enables the STM for broadwell_de by setting CONFIG_VMX Change-Id: I8292bb4eec516556ad1ba658c80ad8a0b541139f Signed-off-by: Eugene Myers Reviewed-on: https://review.coreboot.org/c/coreboot/+/55626 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer --- src/soc/intel/fsp_broadwell_de/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/soc/intel/fsp_broadwell_de/Kconfig b/src/soc/intel/fsp_broadwell_de/Kconfig index 0186e85d13..17a15f6d3b 100644 --- a/src/soc/intel/fsp_broadwell_de/Kconfig +++ b/src/soc/intel/fsp_broadwell_de/Kconfig @@ -95,6 +95,10 @@ config HPET_MIN_TICKS hex default 0x80 +config ENABLE_VMX + bool "Enable VMX for virtualization" + default y + ## Broadwell-DE Specific FSP Kconfig source src/soc/intel/fsp_broadwell_de/fsp/Kconfig From 0f93a91548c254c7759174b333e51edb65a95712 Mon Sep 17 00:00:00 2001 From: Eugene Myers Date: Tue, 11 May 2021 08:33:07 -0400 Subject: [PATCH 62/67] security/intel/stm: Reset BIOS resource list on every stm_setup call Some platforms run the smm_relocation function twice during initialization. This results in the BIOS resource list becoming twice as long. Also, testing has shown that elements of the list created in the first interation may have invalid data included in the resource list. This patch resolves these issues by reseting the list every time stm_setup is involked. This patch has been tested on the Purism L1UM-1X8C Change-Id: I874871ff01bdf0d00a3e6b48bc885e7abaa25112 Signed-off-by: Eugene Myers Reviewed-on: https://review.coreboot.org/c/coreboot/+/55627 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer --- src/security/intel/stm/StmPlatformResource.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/security/intel/stm/StmPlatformResource.c b/src/security/intel/stm/StmPlatformResource.c index 6fef515052..7aa432de40 100644 --- a/src/security/intel/stm/StmPlatformResource.c +++ b/src/security/intel/stm/StmPlatformResource.c @@ -179,8 +179,12 @@ static void add_msr_resources(void) /* * Add resources to BIOS resource database. */ + +extern uint8_t *m_stm_resources_ptr; + void add_resources_cmd(void) { + m_stm_resources_ptr = NULL; add_simple_resources(); From e7e2bd2a593e95fb8fe7b4020a6822ce9cd8a1ff Mon Sep 17 00:00:00 2001 From: Eugene Myers Date: Wed, 12 May 2021 07:55:28 -0400 Subject: [PATCH 63/67] cpu/x86/: Centralize MSEG location calculation This patch centralizes the MSEG location calculation. In the current implementation, the calculation happens in smm_module_loader and mp_init. When smm_module_loaderv2 was added, this calculation became broken as the original calculation made assumptions based on perm_smbase. The calculation is now located in smm_subregion (tseg_region.c), as the MSEG is located within the TSEG (or SMM); These patches have been tested on a Purism librem-l1um server. Change-Id: Ic17e1a505401c3b2a218826dffae6fe12a5c15c6 Signed-off-by: Eugene Myers Reviewed-on: https://review.coreboot.org/c/coreboot/+/55628 Reviewed-by: Stefan Reinauer Tested-by: build bot (Jenkins) --- src/cpu/x86/mp_init.c | 4 ++-- src/cpu/x86/smm/smm_module_loader.c | 2 +- src/cpu/x86/smm/smm_module_loaderv2.c | 4 ++-- src/cpu/x86/smm/tseg_region.c | 16 +++++++++++++--- src/include/cpu/x86/smm.h | 2 ++ 5 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/cpu/x86/mp_init.c b/src/cpu/x86/mp_init.c index 57b88653c5..313fb34113 100644 --- a/src/cpu/x86/mp_init.c +++ b/src/cpu/x86/mp_init.c @@ -756,9 +756,9 @@ static void asmlinkage smm_do_relocation(void *arg) if (CONFIG(STM)) { if (is_smm_enabled()) { uintptr_t mseg; + size_t mseg_size; - mseg = mp_state.perm_smbase + - (mp_state.perm_smsize - CONFIG_MSEG_SIZE); + smm_subregion(SMM_SUBREGION_MSEG, &mseg, &mseg_size); stm_setup(mseg, p->cpu, runtime->num_cpus, perm_smbase, diff --git a/src/cpu/x86/smm/smm_module_loader.c b/src/cpu/x86/smm/smm_module_loader.c index 19acea60d6..dd00b7f05c 100644 --- a/src/cpu/x86/smm/smm_module_loader.c +++ b/src/cpu/x86/smm/smm_module_loader.c @@ -368,7 +368,7 @@ int smm_load_module(void *smram, size_t size, struct smm_loader_params *params) base += size; if (CONFIG(STM)) - base -= CONFIG_MSEG_SIZE + CONFIG_BIOS_RESOURCE_LIST_SIZE; + base -= CONFIG_BIOS_RESOURCE_LIST_SIZE; params->stack_top = base; diff --git a/src/cpu/x86/smm/smm_module_loaderv2.c b/src/cpu/x86/smm/smm_module_loaderv2.c index 04654f77c9..8d01b3c0ee 100644 --- a/src/cpu/x86/smm/smm_module_loaderv2.c +++ b/src/cpu/x86/smm/smm_module_loaderv2.c @@ -586,8 +586,8 @@ int smm_load_module(void *smram, size_t size, struct smm_loader_params *params) /* MSEG starts at the top of SMRAM and works down */ if (CONFIG(STM)) { - base -= CONFIG_MSEG_SIZE + CONFIG_BIOS_RESOURCE_LIST_SIZE; - total_size += CONFIG_MSEG_SIZE + CONFIG_BIOS_RESOURCE_LIST_SIZE; + base -= CONFIG_BIOS_RESOURCE_LIST_SIZE; + total_size += CONFIG_BIOS_RESOURCE_LIST_SIZE; } /* FXSAVE goes below MSEG */ diff --git a/src/cpu/x86/smm/tseg_region.c b/src/cpu/x86/smm/tseg_region.c index a8b8bb7b9a..747dacdca6 100644 --- a/src/cpu/x86/smm/tseg_region.c +++ b/src/cpu/x86/smm/tseg_region.c @@ -17,6 +17,7 @@ #include #include #include +#include /* * Subregions within SMM @@ -25,6 +26,8 @@ * +-------------------------+ * | External Stage Cache | SMM_RESERVED_SIZE * +-------------------------+ + * | STM | MSEG_SIZE + * +-------------------------+ * | code and data | * | (TSEG) | * +-------------------------+ TSEG @@ -35,17 +38,24 @@ int smm_subregion(int sub, uintptr_t *start, size_t *size) size_t sub_size; const size_t ied_size = CONFIG_IED_REGION_SIZE; const size_t cache_size = CONFIG_SMM_RESERVED_SIZE; + const size_t mseg_size = CONFIG_MSEG_SIZE; smm_region(&sub_base, &sub_size); ASSERT(IS_ALIGNED(sub_base, sub_size)); - ASSERT(sub_size > (cache_size + ied_size)); + ASSERT(sub_size > (cache_size + ied_size + mseg_size)); switch (sub) { case SMM_SUBREGION_HANDLER: /* Handler starts at the base of TSEG. */ sub_size -= ied_size; sub_size -= cache_size; + sub_size -= mseg_size; + break; + case SMM_SUBREGION_MSEG: + /* MSEG follows the SMM HANDLER subregion */ + sub_base += sub_size - (ied_size + cache_size + mseg_size); + sub_size = mseg_size; break; case SMM_SUBREGION_CACHE: /* External cache is in the middle of TSEG. */ @@ -88,11 +98,11 @@ void smm_list_regions(void) return; printk(BIOS_DEBUG, "SMM Memory Map\n"); - printk(BIOS_DEBUG, "SMRAM : 0x%zx 0x%zx\n", base, size); + printk(BIOS_DEBUG, "SMRAM : 0x%" PRIxPTR " 0x%zx\n", base, size); for (i = 0; i < SMM_SUBREGION_NUM; i++) { if (smm_subregion(i, &base, &size)) continue; - printk(BIOS_DEBUG, " Subregion %d: 0x%zx 0x%zx\n", i, base, size); + printk(BIOS_DEBUG, " Subregion %d: 0x%" PRIxPTR " 0x%zx\n", i, base, size); } } diff --git a/src/include/cpu/x86/smm.h b/src/include/cpu/x86/smm.h index d8f6d0e627..b4492963b3 100644 --- a/src/include/cpu/x86/smm.h +++ b/src/include/cpu/x86/smm.h @@ -168,6 +168,8 @@ void smm_region(uintptr_t *start, size_t *size); enum { /* SMM handler area. */ SMM_SUBREGION_HANDLER, + /* MSEG (STM). */ + SMM_SUBREGION_MSEG, /* SMM cache region. */ SMM_SUBREGION_CACHE, /* Chipset specific area. */ From 34010e8adba63dbda210cca4185d9f9876b11b87 Mon Sep 17 00:00:00 2001 From: Eugene Myers Date: Wed, 16 Jun 2021 06:18:20 -0400 Subject: [PATCH 64/67] security/intel/stm: Make sure stm_resource_heap is consistent When a parallel SMM relocation is being done, there is a good chance that the value for stm_resource_heap is not consistent across processors. Rather than holding (via a lock) processors until this value is set and then flushing the cache so that all processors see the same value, this solution moves the code such that all processors set it, thus maintaining parallelism and keeping the code simple. Change-Id: I2e5385c47124adcd99803337167984b6307af860 Signed-off-by: Eugene Myers Reviewed-on: https://review.coreboot.org/c/coreboot/+/55629 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer --- src/security/intel/stm/StmPlatformSmm.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/security/intel/stm/StmPlatformSmm.c b/src/security/intel/stm/StmPlatformSmm.c index 248ccc028a..3f29afc096 100644 --- a/src/security/intel/stm/StmPlatformSmm.c +++ b/src/security/intel/stm/StmPlatformSmm.c @@ -173,12 +173,15 @@ void stm_setup(uintptr_t mseg, int cpu, int num_cpus, uintptr_t smbase, return; } + // This code moved here because paralled SMM setup can cause some + // processors to get a bad value. + addr_calc = mseg - CONFIG_BIOS_RESOURCE_LIST_SIZE; + stm_resource_heap = (uint8_t *) addr_calc; + if (cpu == 0) { // need to create the BIOS resource list once // first calculate the location in SMRAM - addr_calc = mseg - CONFIG_BIOS_RESOURCE_LIST_SIZE; - stm_resource_heap = (uint8_t *) addr_calc; printk(BIOS_DEBUG, "STM: stm_resource_heap located at %p\n", stm_resource_heap); //setup the the list From 92c1a19c79df22206e51c7506d1f75c653dcb54f Mon Sep 17 00:00:00 2001 From: Eugene Myers Date: Thu, 17 Jun 2021 04:59:27 -0400 Subject: [PATCH 65/67] security/intel/stm: Provide MSEG too small diagnostic information This patch provides diagnostic information during the STM setup to indicate when the MSEG is too small for what the STM requires. The error message includes the configured MSEG size and the MSEG area that the STM needs. Change-Id: I88d947e3a0495089be886f6557e4d4d7993e2508 Signed-off-by: Eugene Myers Reviewed-on: https://review.coreboot.org/c/coreboot/+/55630 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer --- src/security/intel/stm/SmmStm.c | 154 +++++++++++++------------------- 1 file changed, 60 insertions(+), 94 deletions(-) diff --git a/src/security/intel/stm/SmmStm.c b/src/security/intel/stm/SmmStm.c index 523a63f420..e6f4c0ad61 100644 --- a/src/security/intel/stm/SmmStm.c +++ b/src/security/intel/stm/SmmStm.c @@ -39,8 +39,7 @@ #define STM_PAGE_SHIFT 12 #define STM_PAGE_MASK 0xFFF -#define STM_SIZE_TO_PAGES(a) \ - (((a) >> STM_PAGE_SHIFT) + (((a)&STM_PAGE_MASK) ? 1 : 0)) +#define STM_SIZE_TO_PAGES(a) (((a) >> STM_PAGE_SHIFT) + (((a)&STM_PAGE_MASK) ? 1 : 0)) #define STM_PAGES_TO_SIZE(a) ((a) << STM_PAGE_SHIFT) #define STM_ACCESS_DENIED 15 @@ -137,13 +136,10 @@ static bool handle_single_resource(STM_RSC *resource, STM_RSC *record) resource_hi = resource->mem.base + resource->mem.length; record_lo = record->mem.base; record_hi = record->mem.base + record->mem.length; - if (resource->mem.rwx_attributes - != record->mem.rwx_attributes) { - if ((resource_lo == record_lo) - && (resource_hi == record_hi)) { - record->mem.rwx_attributes = - resource->mem.rwx_attributes - | record->mem.rwx_attributes; + if (resource->mem.rwx_attributes != record->mem.rwx_attributes) { + if ((resource_lo == record_lo) && (resource_hi == record_hi)) { + record->mem.rwx_attributes = resource->mem.rwx_attributes + | record->mem.rwx_attributes; return true; } else { return false; @@ -153,39 +149,31 @@ static bool handle_single_resource(STM_RSC *resource, STM_RSC *record) case IO_RANGE: case TRAPPED_IO_RANGE: resource_lo = (uint64_t)resource->io.base; - resource_hi = (uint64_t)resource->io.base - + (uint64_t)resource->io.length; + resource_hi = (uint64_t)resource->io.base + (uint64_t)resource->io.length; record_lo = (uint64_t)record->io.base; - record_hi = - (uint64_t)record->io.base + (uint64_t)record->io.length; + record_hi = (uint64_t)record->io.base + (uint64_t)record->io.length; break; case PCI_CFG_RANGE: if ((resource->pci_cfg.originating_bus_number != record->pci_cfg.originating_bus_number) - || (resource->pci_cfg.last_node_index - != record->pci_cfg.last_node_index)) + || (resource->pci_cfg.last_node_index != record->pci_cfg.last_node_index)) return false; - if (memcmp(resource->pci_cfg.pci_device_path, - record->pci_cfg.pci_device_path, + if (memcmp(resource->pci_cfg.pci_device_path, record->pci_cfg.pci_device_path, sizeof(STM_PCI_DEVICE_PATH_NODE) * (resource->pci_cfg.last_node_index + 1)) != 0) { return false; } resource_lo = (uint64_t)resource->pci_cfg.base; - resource_hi = (uint64_t)resource->pci_cfg.base - + (uint64_t)resource->pci_cfg.length; + resource_hi = + (uint64_t)resource->pci_cfg.base + (uint64_t)resource->pci_cfg.length; record_lo = (uint64_t)record->pci_cfg.base; - record_hi = (uint64_t)record->pci_cfg.base - + (uint64_t)record->pci_cfg.length; - if (resource->pci_cfg.rw_attributes - != record->pci_cfg.rw_attributes) { - if ((resource_lo == record_lo) - && (resource_hi == record_hi)) { - record->pci_cfg.rw_attributes = - resource->pci_cfg.rw_attributes - | record->pci_cfg.rw_attributes; + record_hi = (uint64_t)record->pci_cfg.base + (uint64_t)record->pci_cfg.length; + if (resource->pci_cfg.rw_attributes != record->pci_cfg.rw_attributes) { + if ((resource_lo == record_lo) && (resource_hi == record_hi)) { + record->pci_cfg.rw_attributes = resource->pci_cfg.rw_attributes + | record->pci_cfg.rw_attributes; return true; } else { return false; @@ -256,8 +244,7 @@ static void add_single_resource(STM_RSC *resource) // Go to next record if resource and record types don't match. if (resource->header.rsc_type != record->header.rsc_type) { - record = (STM_RSC *)((void *)record - + record->header.length); + record = (STM_RSC *)((void *)record + record->header.length); continue; } @@ -268,15 +255,13 @@ static void add_single_resource(STM_RSC *resource) } // Add resource to the end of area. - memcpy(m_stm_resources_ptr + m_stm_resource_size_used - - sizeof(m_rsc_end_node), + memcpy(m_stm_resources_ptr + m_stm_resource_size_used - sizeof(m_rsc_end_node), resource, resource->header.length); - memcpy(m_stm_resources_ptr + m_stm_resource_size_used - - sizeof(m_rsc_end_node) + resource->header.length, + memcpy(m_stm_resources_ptr + m_stm_resource_size_used - sizeof(m_rsc_end_node) + + resource->header.length, &m_rsc_end_node, sizeof(m_rsc_end_node)); m_stm_resource_size_used += resource->header.length; - m_stm_resource_size_available = - m_stm_resource_total_size - m_stm_resource_size_used; + m_stm_resource_size_available = m_stm_resource_total_size - m_stm_resource_size_used; } /* @@ -303,8 +288,7 @@ static void add_resource(STM_RSC *resource_list, uint32_t num_entries) if (resource->header.rsc_type == END_OF_RESOURCES) return; add_single_resource(resource); - resource = - (STM_RSC *)((void *)resource + resource->header.length); + resource = (STM_RSC *)((void *)resource + resource->header.length); } } @@ -336,11 +320,8 @@ static bool validate_resource(STM_RSC *resource_list, uint32_t num_entries) resource = resource_list; for (index = 0; index < count; index++) { - printk(BIOS_DEBUG, "STM: %s (%u) - RscType(%x) length(0x%x)\n", - __func__, - index, - resource->header.rsc_type, - resource->header.length); + printk(BIOS_DEBUG, "STM: %s (%u) - RscType(%x) length(0x%x)\n", __func__, index, + resource->header.rsc_type, resource->header.length); // Validate resource. switch (resource->header.rsc_type) { case END_OF_RESOURCES: @@ -360,11 +341,8 @@ static bool validate_resource(STM_RSC *resource_list, uint32_t num_entries) case MEM_RANGE: case MMIO_RANGE: - printk(BIOS_DEBUG, - "STM: %s - MEM (0x%0llx, 0x%0llx)\n", - __func__, - resource->mem.base, - resource->mem.length); + printk(BIOS_DEBUG, "STM: %s - MEM (0x%0llx, 0x%0llx)\n", __func__, + resource->mem.base, resource->mem.length); if (resource->header.length != sizeof(STM_RSC_MEM_DESC)) return false; @@ -383,34 +361,26 @@ static bool validate_resource(STM_RSC *resource_list, uint32_t num_entries) break; case PCI_CFG_RANGE: - printk(BIOS_DEBUG, - "STM: %s - PCI (0x%02x, 0x%08x, 0x%02x, 0x%02x)\n", - __func__, - resource->pci_cfg.originating_bus_number, + printk(BIOS_DEBUG, "STM: %s - PCI (0x%02x, 0x%08x, 0x%02x, 0x%02x)\n", + __func__, resource->pci_cfg.originating_bus_number, resource->pci_cfg.last_node_index, resource->pci_cfg.pci_device_path[0].pci_device, - resource->pci_cfg.pci_device_path[0] - .pci_function); + resource->pci_cfg.pci_device_path[0].pci_function); if (resource->header.length != sizeof(STM_RSC_PCI_CFG_DESC) + (sizeof(STM_PCI_DEVICE_PATH_NODE) * resource->pci_cfg.last_node_index)) return false; - for (sub_index = 0; - sub_index <= resource->pci_cfg.last_node_index; + for (sub_index = 0; sub_index <= resource->pci_cfg.last_node_index; sub_index++) { - if ((resource->pci_cfg - .pci_device_path[sub_index] - .pci_device + if ((resource->pci_cfg.pci_device_path[sub_index].pci_device > 0x1F) - || (resource->pci_cfg - .pci_device_path[sub_index] + || (resource->pci_cfg.pci_device_path[sub_index] .pci_function > 7)) return false; } - if ((resource->pci_cfg.base + resource->pci_cfg.length) - > 0x1000) + if ((resource->pci_cfg.base + resource->pci_cfg.length) > 0x1000) return false; break; @@ -420,12 +390,11 @@ static bool validate_resource(STM_RSC *resource_list, uint32_t num_entries) break; default: - printk(BIOS_DEBUG, "STM: %s - Unknown RscType(%x)\n", - __func__, resource->header.rsc_type); + printk(BIOS_DEBUG, "STM: %s - Unknown RscType(%x)\n", __func__, + resource->header.rsc_type); return false; } - resource = - (STM_RSC *)((void *)resource + resource->header.length); + resource = (STM_RSC *)((void *)resource + resource->header.length); } return true; } @@ -462,8 +431,7 @@ static uint32_t get_resource_size(STM_RSC *resource_list, uint32_t num_entries) for (index = 0; index < count; index++) { if (resource->header.rsc_type == END_OF_RESOURCES) break; - resource = - (STM_RSC *)((void *)resource + resource->header.length); + resource = (STM_RSC *)((void *)resource + resource->header.length); } return (uint32_t)((uint32_t)resource - (uint32_t)resource_list); } @@ -490,7 +458,7 @@ int add_pi_resource(STM_RSC *resource_list, uint32_t num_entries) return -1; // INVALID_PARAMETER; resource_size = get_resource_size(resource_list, num_entries); - printk(BIOS_DEBUG, "STM: ResourceSize - 0x%08x\n", (int) resource_size); + printk(BIOS_DEBUG, "STM: ResourceSize - 0x%08x\n", (int)resource_size); if (resource_size == 0) return -1; // INVALID_PARAMETER; @@ -501,8 +469,7 @@ int add_pi_resource(STM_RSC *resource_list, uint32_t num_entries) m_stm_resource_total_size = CONFIG_BIOS_RESOURCE_LIST_SIZE; memset(m_stm_resources_ptr, 0, CONFIG_BIOS_RESOURCE_LIST_SIZE); - memcpy(m_stm_resources_ptr, &m_rsc_end_node, - sizeof(m_rsc_end_node)); + memcpy(m_stm_resources_ptr, &m_rsc_end_node, sizeof(m_rsc_end_node)); m_stm_resource_size_used = sizeof(m_rsc_end_node); m_stm_resource_size_available = m_stm_resource_total_size - sizeof(m_rsc_end_node); @@ -511,7 +478,7 @@ int add_pi_resource(STM_RSC *resource_list, uint32_t num_entries) } else { if (m_stm_resource_size_available < resource_size) { printk(BIOS_DEBUG, - "STM: ERROR - not enough space for SMM resource list\n"); + "STM: ERROR - not enough space for SMM resource list\n"); return -1; // OUT_OF_RESOURCES } } @@ -543,8 +510,7 @@ int32_t delete_pi_resource(STM_RSC *resource_list, uint32_t num_entries) // Delete all memcpy(m_stm_resources_ptr, &m_rsc_end_node, sizeof(m_rsc_end_node)); m_stm_resource_size_used = sizeof(m_rsc_end_node); - m_stm_resource_size_available = - m_stm_resource_total_size - sizeof(m_rsc_end_node); + m_stm_resource_size_available = m_stm_resource_total_size - sizeof(m_rsc_end_node); return 0; // SUCCESS; } @@ -587,8 +553,8 @@ static uint32_t get_vmcs_size(void) this_vmcs_size = msr_data64.bits.vmcs_size; stm_support = msr_data64.bits.stm_supported; - printk(BIOS_DEBUG, "STM: %s: Size %d StmSupport %d\n", __func__, - this_vmcs_size, stm_support); + printk(BIOS_DEBUG, "STM: %s: Size %d StmSupport %d\n", __func__, this_vmcs_size, + stm_support); // VMCS require 0x1000 alignment this_vmcs_size = STM_PAGES_TO_SIZE(STM_SIZE_TO_PAGES(this_vmcs_size)); @@ -623,10 +589,9 @@ void stm_gen_4g_pagetable_x64(uint32_t pagetable_base) pde++; pagetable_base += PTP_SIZE; - for (sub_index = 0; sub_index < SIZE_4KB / sizeof(*pte); - sub_index++) { - *pte = (((index << 9) + sub_index) << 21) | IA32_PG_PS - | IA32_PG_RW | IA32_PG_P; + for (sub_index = 0; sub_index < SIZE_4KB / sizeof(*pte); sub_index++) { + *pte = (((index << 9) + sub_index) << 21) | IA32_PG_PS | IA32_PG_RW + | IA32_PG_P; pte++; } } @@ -650,30 +615,31 @@ bool stm_check_stm_image(void *stm_image, uint32_t stm_imagesize) stm_header = (STM_HEADER *)stm_image; // Get Minimal required Mseg size - min_mseg_size = (STM_PAGES_TO_SIZE(STM_SIZE_TO_PAGES( - stm_header->sw_stm_hdr.static_image_size)) - + stm_header->sw_stm_hdr.additional_dynamic_memory_size - + (stm_header->sw_stm_hdr.per_proc_dynamic_memory_size - + get_vmcs_size() * 2) - * mp_state.cpu_count); + min_mseg_size = + (STM_PAGES_TO_SIZE(STM_SIZE_TO_PAGES(stm_header->sw_stm_hdr.static_image_size)) + + stm_header->sw_stm_hdr.additional_dynamic_memory_size + + (stm_header->sw_stm_hdr.per_proc_dynamic_memory_size + get_vmcs_size() * 2) + * mp_state.cpu_count); if (min_mseg_size < stm_imagesize) min_mseg_size = stm_imagesize; - if (stm_header->hw_stm_hdr.cr3_offset - >= stm_header->sw_stm_hdr.static_image_size) { + if (stm_header->hw_stm_hdr.cr3_offset >= stm_header->sw_stm_hdr.static_image_size) { // We will create page table, just in case that SINIT does not // create it. - if (min_mseg_size < stm_header->hw_stm_hdr.cr3_offset - + STM_PAGES_TO_SIZE(6)) { - min_mseg_size = stm_header->hw_stm_hdr.cr3_offset - + STM_PAGES_TO_SIZE(6); + if (min_mseg_size < stm_header->hw_stm_hdr.cr3_offset + STM_PAGES_TO_SIZE(6)) { + min_mseg_size = + stm_header->hw_stm_hdr.cr3_offset + STM_PAGES_TO_SIZE(6); } } // Check if it exceeds MSEG size - if (min_mseg_size > CONFIG_MSEG_SIZE) + if (min_mseg_size > CONFIG_MSEG_SIZE) { + printk(BIOS_ERR, + "STM: ERROR - Configured MSEG size 0x%x less than required MSEG size 0x%x\n", + CONFIG_MSEG_SIZE, min_mseg_size); return false; + } return true; } From 1c13f8d85c7306213cd525308ee8973e5663a3f8 Mon Sep 17 00:00:00 2001 From: Eugene Myers Date: Wed, 16 Jun 2021 09:12:33 -0400 Subject: [PATCH 66/67] security/intel/stm/Makefile.inc: Fix typo In both the Kconfig and Makefile in this directory, "STM_TTYS0_BASE" is used. Therefore, fix the typo. Original-Change-Id: Ie83ec31c7bb0f6805c0225ee7405e137a666a5d3 Original-Signed-off-by: Benjamin Doron Original-Reviewed-on: https://review.coreboot.org/c/coreboot/+/51206 Original-Reviewed-by: Angel Pons Original-Reviewed-by: Eugene Myers Original-Tested-by: build bot (Jenkins) Change-Id: I8aa81a51380d48b172284e534ffd203f30a10286 Signed-off-by: Eugene Myers Reviewed-on: https://review.coreboot.org/c/coreboot/+/55624 Reviewed-by: Stefan Reinauer Tested-by: build bot (Jenkins) --- src/security/intel/stm/Makefile.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/security/intel/stm/Makefile.inc b/src/security/intel/stm/Makefile.inc index 3f5b9ee5c6..d4da605bd7 100644 --- a/src/security/intel/stm/Makefile.inc +++ b/src/security/intel/stm/Makefile.inc @@ -11,7 +11,7 @@ ramstage-$(CONFIG_STM) += StmPlatformResource.c 3rdparty/stm/Stm/build/StmPkg/Core/stm.bin: $(obj)/config.h $(MAKE) -C src/security/intel/stm \ - CONFIG_STM_TTYSO_BASE=$(CONFIG_STM_TTYSO_BASE) \ + CONFIG_STM_TTYS0_BASE=$(CONFIG_STM_TTYS0_BASE) \ CONFIG_STM_HEAPSIZE=$(CONFIG_STM_HEAPSIZE) \ CONFIG_STM_CONSOLE_DEBUG=$(CONFIG_STM_CONSOLE_DEBUG) \ CONFIG_STM_CONSOLE_RELEASE=$(CONFIG_STM_CONSOLE_RELEASE) \ From 046814c2703b8fd0030ad026bf42e153bbe41db4 Mon Sep 17 00:00:00 2001 From: Paul Menzel Date: Sun, 2 Oct 2022 20:17:04 +0200 Subject: [PATCH 67/67] Makefile.inc: Decrease minimal pagesize from 4 kB to 1 kB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GCC 12 incorrectly warns about an array out of bounds issue: ``` $ make V=1 # emulation/qemu-i440fx […] CC ramstage/arch/x86/ebda.o x86_64-linux-gnu-gcc-12 -MMD -Isrc -Isrc/include -Isrc/commonlib/include -Isrc/commonlib/bsd/include -Ibuild -I3rdparty/vboot/firmware/include -include src/include/kconfig.h -include src/include/rules.h -include src/commonlib/bsd/include/commonlib/bsd/compiler.h -I3rdparty -D__BUILD_DIR__=\"build\" -Isrc/arch/x86/include -D__ARCH_x86_32__ -pipe -g -nostdinc -std=gnu11 -nostdlib -Wall -Wundef -Wstrict-prototypes -Wmissing-prototypes -Wwrite-strings -Wredundant-decls -Wno-trigraphs -Wimplicit-fallthrough -Wshadow -Wdate-time -Wtype-limits -Wvla -Wdangling-else -fno-common -ffreestanding -fno-builtin -fomit-frame-pointer -fstrict-aliasing -ffunction-sections -fdata-sections -fno-pie -Wno-packed-not-aligned -fconserve-stack -Wnull-dereference -Wreturn-type -Wlogical-op -Wduplicated-cond -Wno-unused-but-set-variable -Werror -Os -Wno-address-of-packed-member -m32 -Wl,-b,elf32-i386 -Wl,-melf_i386 -m32 -fuse-ld=bfd -fno-stack-protector -Wl,--build-id=none -fno-delete-null-pointer-checks -Wlogical-op -march=i686 -mno-mmx -MT build/ramstage/arch/x86/ebda.o -D__RAMSTAGE__ -c -o build/ramstage/arch/x86/ebda.o src/arch/x86/ebda.c In file included from src/arch/x86/ebda.c:6: In function 'write_ble8', inlined from 'write_le8' at src/commonlib/include/commonlib/endian.h:155:2, inlined from 'write_le16' at src/commonlib/include/commonlib/endian.h:178:2, inlined from 'setup_ebda' at src/arch/x86/ebda.c:35:2, inlined from 'setup_default_ebda' at src/arch/x86/ebda.c:48:2: src/commonlib/include/commonlib/endian.h:27:26: error: array subscript 0 is outside array bounds of 'void[0]' [-Werror=array-bounds] 27 | *(uint8_t *)dest = val; | ~~~~~~~~~~~~~~~~~^~~~~ […] ``` [In GCC 12 the new parameter `min-pagesize` is added and defaults 4 kB.][1] It treats INTEGER_CST addresses smaller than that as assumed results of pointer arithmetics from NULL while addresses equal or larger than that as expected user constant addresses. For GCC 13 we can represent results from pointer arithmetics on NULL using &MEM[(void*)0 + offset] instead of (void*)offset INTEGER_CSTs. [1]: https://web.archive.org/web/20220711061810/https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99578 TEST=No compile error with gcc (Debian 12.2.0-3) 12.2.0 Change-Id: I6e36633f42cb4dc5af53212c10c919a86e451ee0 Original-Signed-off-by: Paul Menzel Original-Reviewed-on: https://review.coreboot.org/c/coreboot/+/62830 Original-Tested-by: build bot (Jenkins) Original-Reviewed-by: Angel Pons Reviewed-on: https://review.coreboot.org/c/coreboot/+/81785 Tested-by: Felix Singer Reviewed-by: Felix Singer Reviewed-by: Angel Pons --- util/xcompile/xcompile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/util/xcompile/xcompile b/util/xcompile/xcompile index 2d3da1e00e..13273240c5 100755 --- a/util/xcompile/xcompile +++ b/util/xcompile/xcompile @@ -184,7 +184,8 @@ detect_special_flags() { CFLAGS_GCC="$CFLAGS_GCC -fno-stack-protector" testcc "$GCC" "$CFLAGS_GCC -Wl,--build-id=none" && CFLAGS_GCC="$CFLAGS_GCC -Wl,--build-id=none" - + testcc "$GCC" "$CFLAGS_GCC --param=min-pagesize=1024 $FLAGS_GCC" && + CFLAGS_GCC="$CFLAGS_GCC --param=min-pagesize=1024" case "$architecture" in x86) ;;