summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configs/config.stm4
-rw-r--r--src/cpu/x86/mp_init.c34
-rw-r--r--src/cpu/x86/smm/smm_module_loader.c19
-rw-r--r--src/cpu/x86/smm/smm_stub.S13
-rw-r--r--src/include/cpu/x86/msr.h10
-rw-r--r--src/include/cpu/x86/smm.h3
-rw-r--r--src/security/intel/Kconfig1
-rw-r--r--src/security/intel/Makefile.inc1
-rw-r--r--src/security/intel/stm/Kconfig49
-rw-r--r--src/security/intel/stm/Makefile.inc10
-rw-r--r--src/security/intel/stm/SmmStm.c691
-rw-r--r--src/security/intel/stm/SmmStm.h120
-rw-r--r--src/security/intel/stm/StmApi.h726
-rw-r--r--src/security/intel/stm/StmPlatformResource.c188
-rw-r--r--src/security/intel/stm/StmPlatformResource.h32
-rw-r--r--src/security/intel/stm/StmPlatformSmm.c204
16 files changed, 2104 insertions, 1 deletions
diff --git a/configs/config.stm b/configs/config.stm
new file mode 100644
index 000000000000..59792b2fa518
--- /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 b093be700303..331f3b552a86 100644
--- a/src/cpu/x86/mp_init.c
+++ b/src/cpu/x86/mp_init.c
@@ -38,6 +38,8 @@
#include <timer.h>
#include <thread.h>
+#include <security/intel/stm/SmmStm.h>
+
#define MAX_APIC_IDS 256
struct mp_callback {
@@ -743,6 +745,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)
@@ -1023,6 +1042,21 @@ static void fill_mp_state(struct mp_state *state, const struct mp_ops *ops)
&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 c6c6b3873769..a421436893fa 100644
--- a/src/cpu/x86/smm/smm_module_loader.c
+++ b/src/cpu/x86/smm/smm_module_loader.c
@@ -17,6 +17,7 @@
#include <cpu/x86/cache.h>
#include <commonlib/helpers.h>
#include <console/console.h>
+#include <security/intel/stm/SmmStm.h>
#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 f0e55f9a18e9..8207d233a055 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 63cb8bde282f..49abd41c0005 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 cf107b121afa..9efe2e04ebe4 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 a4525e7b9bad..aa24e8ac68ab 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 9388d3f79802..e00802ad06a1 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 000000000000..a74eba85228a
--- /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 000000000000..1a23fe97f2c5
--- /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 000000000000..f23be70217ef
--- /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 <console/console.h>
+#include <cpu/x86/cr.h>
+#include <cpu/x86/mp.h>
+#include <cpu/x86/msr.h>
+#include <cpu/x86/cache.h>
+#include <security/intel/stm/SmmStm.h>
+#include <string.h>
+
+#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 000000000000..4f72816caeaa
--- /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 <cpu/x86/msr.h>
+#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 000000000000..342ceeacf604
--- /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 <stdint.h>
+
+// 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 000000000000..6fef515052f0
--- /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 <stdint.h>
+#include <security/intel/stm/StmApi.h>
+#include <security/intel/stm/SmmStm.h>
+#include <security/intel/stm/StmPlatformResource.h>
+
+#if CONFIG(SOUTHBRIDGE_INTEL_COMMON_PMCLIB)
+#include <southbridge/intel/common/pmutil.h>
+#else
+#include <soc/pm.h>
+#endif
+#include <cpu/x86/msr.h>
+#include <console/console.h>
+
+#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 000000000000..7db2fc0330f2
--- /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 000000000000..d7064b07f5b1
--- /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 <security/intel/stm/StmApi.h>
+#include <security/intel/stm/SmmStm.h>
+#include <security/intel/stm/StmPlatformResource.h>
+#include <security/tpm/tspi.h>
+#include <cpu/x86/smm.h>
+#include <cpu/x86/msr.h>
+
+#include <stddef.h>
+#include <cbfs.h>
+#include <console/console.h>
+#include <lib.h>
+#include <stdint.h>
+#include <arch/rom_segs.h>
+
+/*
+ * 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);
+ }
+}