summaryrefslogtreecommitdiffstats
path: root/tboot/acmod.c
diff options
context:
space:
mode:
Diffstat (limited to 'tboot/acmod.c')
-rw-r--r--tboot/acmod.c991
1 files changed, 991 insertions, 0 deletions
diff --git a/tboot/acmod.c b/tboot/acmod.c
new file mode 100644
index 0000000..6601222
--- /dev/null
+++ b/tboot/acmod.c
@@ -0,0 +1,991 @@
+/*
+ * acmod.c: support functions for use of Intel(r) TXT Authenticated
+ * Code (AC) Modules
+ *
+ * Copyright (c) 2003-2011, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef IS_INCLUDED /* defined in utils/acminfo.c */
+#include <config.h>
+#include <efibase.h>
+#include <types.h>
+#include <stdbool.h>
+#include <printk.h>
+#include <compiler.h>
+#include <string.h>
+#include <processor.h>
+#include <msr.h>
+#include <misc.h>
+#include <uuid.h>
+#include <mle.h>
+#include <hash.h>
+#include <txt/acmod.h>
+#include <txt/config_regs.h>
+#include <txt/mtrrs.h>
+#include <txt/heap.h>
+#include <txt/smx.h>
+#include <tpm.h>
+#endif /* IS_INCLUDED */
+
+__data acm_hdr_t *g_sinit = 0;
+
+static acm_info_table_t *get_acmod_info_table(const acm_hdr_t* hdr)
+{
+ uint32_t user_area_off;
+
+ /* overflow? */
+ if ( plus_overflow_u32(hdr->header_len, hdr->scratch_size) ) {
+ printk(TBOOT_ERR"ACM header length plus scratch size overflows\n");
+ return NULL;
+ }
+
+ if ( multiply_overflow_u32((hdr->header_len + hdr->scratch_size), 4) ) {
+ printk(TBOOT_ERR"ACM header length and scratch size in bytes overflows\n");
+ return NULL;
+ }
+
+
+ /* this fn assumes that the ACM has already passed at least the initial */
+ /* is_acmod() checks */
+
+ user_area_off = (hdr->header_len + hdr->scratch_size) * 4;
+
+ /* overflow? */
+ if ( plus_overflow_u32(user_area_off, sizeof(acm_info_table_t)) ) {
+ printk(TBOOT_ERR"user_area_off plus acm_info_table_t size overflows\n");
+ return NULL;
+ }
+
+ /* check that table is within module */
+ if ( user_area_off + sizeof(acm_info_table_t) > hdr->size*4 ) {
+ printk(TBOOT_ERR"ACM info table size too large: %x\n",
+ user_area_off + (uint32_t)sizeof(acm_info_table_t));
+ return NULL;
+ }
+
+ /* overflow? */
+ if ( plus_overflow_u64((uint64_t)(uintptr_t)hdr, user_area_off) ) {
+ printk(TBOOT_ERR"hdr plus user_area_off overflows\n");
+ return NULL;
+ }
+
+ return (acm_info_table_t *)((unsigned long long)hdr + user_area_off);
+}
+
+static acm_chipset_id_list_t *get_acmod_chipset_list(const acm_hdr_t* hdr)
+{
+ acm_info_table_t* info_table;
+ uint32_t size, id_list_off;
+ acm_chipset_id_list_t *chipset_id_list;
+
+ /* this fn assumes that the ACM has already passed the is_acmod() checks */
+
+ info_table = get_acmod_info_table(hdr);
+ if ( info_table == NULL )
+ return NULL;
+ id_list_off = info_table->chipset_id_list;
+
+ size = hdr->size * 4;
+
+ /* overflow? */
+ if ( plus_overflow_u32(id_list_off, sizeof(acm_chipset_id_t)) ) {
+ printk(TBOOT_ERR"id_list_off plus acm_chipset_id_t size overflows\n");
+ return NULL;
+ }
+
+ /* check that chipset id table is w/in ACM */
+ if ( id_list_off + sizeof(acm_chipset_id_t) > size ) {
+ printk(TBOOT_ERR"ACM chipset id list is too big: chipset_id_list=%x\n",
+ id_list_off);
+ return NULL;
+ }
+
+ /* overflow? */
+ if ( plus_overflow_u64((uint64_t)(uintptr_t)hdr, id_list_off) ) {
+ printk(TBOOT_ERR"hdr plus id_list_off overflows\n");
+ return NULL;
+ }
+
+ chipset_id_list = (acm_chipset_id_list_t *)
+ ((unsigned long long)hdr + id_list_off);
+
+ /* overflow? */
+ if ( multiply_overflow_u32(chipset_id_list->count,
+ sizeof(acm_chipset_id_t)) ) {
+ printk(TBOOT_ERR"size of acm_chipset_id_list overflows\n");
+ return NULL;
+ }
+ if ( plus_overflow_u32(id_list_off + sizeof(acm_chipset_id_t),
+ chipset_id_list->count * sizeof(acm_chipset_id_t)) ) {
+ printk(TBOOT_ERR"size of all entries overflows\n");
+ return NULL;
+ }
+
+ /* check that all entries are w/in ACM */
+ if ( id_list_off + sizeof(acm_chipset_id_t) +
+ chipset_id_list->count * sizeof(acm_chipset_id_t) > size ) {
+ printk(TBOOT_ERR"ACM chipset id entries are too big:"
+ " chipset_id_list->count=%x\n", chipset_id_list->count);
+ return NULL;
+ }
+
+ return chipset_id_list;
+}
+
+static acm_processor_id_list_t *get_acmod_processor_list(const acm_hdr_t* hdr)
+{
+ acm_info_table_t* info_table;
+ uint32_t size, id_list_off;
+ acm_processor_id_list_t *proc_id_list;
+
+ /* this fn assumes that the ACM has already passed the is_acmod() checks */
+
+ info_table = get_acmod_info_table(hdr);
+ if ( info_table == NULL )
+ return NULL;
+ id_list_off = info_table->processor_id_list;
+
+ size = hdr->size * 4;
+
+ /* overflow? */
+ if ( plus_overflow_u32(id_list_off, sizeof(acm_processor_id_t)) ) {
+ printk(TBOOT_ERR"id_list_off plus acm_processor_id_t size overflows\n");
+ return NULL;
+ }
+
+ /* check that processor id table is w/in ACM */
+ if ( id_list_off + sizeof(acm_processor_id_t) > size ) {
+ printk(TBOOT_ERR"ACM processor id list is too big: processor_id_list=%x\n",
+ id_list_off);
+ return NULL;
+ }
+
+ /* overflow? */
+ if ( plus_overflow_u64((unsigned long long)hdr, id_list_off) ) {
+ printk(TBOOT_ERR"hdr plus id_list_off overflows\n");
+ return NULL;
+ }
+
+ proc_id_list = (acm_processor_id_list_t *)
+ ((unsigned long long)hdr + id_list_off);
+
+ /* overflow? */
+ if ( multiply_overflow_u32(proc_id_list->count,
+ sizeof(acm_processor_id_t)) ) {
+ printk(TBOOT_ERR"size of acm_processor_id_list overflows\n");
+ return NULL;
+ }
+ if ( plus_overflow_u32(id_list_off + sizeof(acm_processor_id_t),
+ proc_id_list->count * sizeof(acm_processor_id_t)) ) {
+ printk(TBOOT_ERR"size of all entries overflows\n");
+ return NULL;
+ }
+
+ /* check that all entries are w/in ACM */
+ if ( id_list_off + sizeof(acm_processor_id_t) +
+ proc_id_list->count * sizeof(acm_processor_id_t) > size ) {
+ printk(TBOOT_ERR"ACM processor id entries are too big:"
+ " proc_id_list->count=%x\n", proc_id_list->count);
+ return NULL;
+ }
+
+ return proc_id_list;
+}
+
+tpm_info_list_t *get_tpm_info_list(const acm_hdr_t* hdr)
+{
+ acm_info_table_t* info_table;
+ uint32_t size, tpm_info_off;
+ tpm_info_list_t *tpm_info;
+
+ /* this fn assumes that the ACM has already passed the is_acmod() checks */
+
+ info_table = get_acmod_info_table(hdr);
+ if ( info_table == NULL )
+ return NULL;
+ tpm_info_off = info_table->tpm_info_list_off;
+
+ size = hdr->size * 4;
+
+ /* overflow? */
+ if ( plus_overflow_u32(tpm_info_off, sizeof(tpm_info_list_t)) ) {
+ printk("tpm_info_off plus tpm_info_list_t size overflows\n");
+ return NULL;
+ }
+
+ /* check that tpm info list is w/in ACM */
+ if ( tpm_info_off + sizeof(tpm_info_list_t) > size ) {
+ printk("TPM info list is too big: tpm_info_list=%x\n",
+ tpm_info_off);
+ return NULL;
+ }
+
+ /* overflow? */
+ if ( plus_overflow_u64((unsigned long long)hdr, tpm_info_off) ) {
+ printk("hdr plus tpm_info_off overflows\n");
+ return NULL;
+ }
+
+ tpm_info = (tpm_info_list_t *)
+ ((unsigned long long)hdr + tpm_info_off);
+
+ /* overflow? */
+ if ( multiply_overflow_u32(tpm_info->count,
+ sizeof(uint16_t)) ) {
+ printk("size of tpm_info_list overflows\n");
+ return NULL;
+ }
+ if ( plus_overflow_u32(tpm_info_off + sizeof(tpm_info_list_t),
+ tpm_info->count * sizeof(uint16_t)) ) {
+ printk("size of all entries overflows\n");
+ return NULL;
+ }
+
+ /* check that all entries are w/in ACM */
+ if ( tpm_info_off + sizeof(tpm_info_list_t) +
+ tpm_info->count * sizeof(uint16_t) > size ) {
+ printk("TPM info list entries are too big:"
+ " tpm_info_list->count=%x\n", tpm_info->count);
+ return NULL;
+ }
+
+ return tpm_info;
+}
+
+void print_txt_caps(const char *prefix, txt_caps_t caps)
+{
+ printk(TBOOT_DETA"%scapabilities: 0x%08x\n", prefix, caps._raw);
+ printk(TBOOT_DETA"%s rlp_wake_getsec: %d\n", prefix, caps.rlp_wake_getsec);
+ printk(TBOOT_DETA"%s rlp_wake_monitor: %d\n", prefix, caps.rlp_wake_monitor);
+ printk(TBOOT_DETA"%s ecx_pgtbl: %d\n", prefix, caps.ecx_pgtbl);
+ printk(TBOOT_DETA"%s stm: %d\n", prefix, caps.stm);
+ printk(TBOOT_DETA"%s pcr_map_no_legacy: %d\n", prefix, caps.pcr_map_no_legacy);
+ printk(TBOOT_DETA"%s pcr_map_da: %d\n", prefix, caps.pcr_map_da);
+ printk(TBOOT_DETA"%s platform_type: %d\n", prefix, caps.platform_type);
+ printk(TBOOT_DETA"%s max_phy_addr: %d\n", prefix, caps.max_phy_addr);
+}
+
+static void print_acm_hdr(const acm_hdr_t *hdr, const char *mod_name)
+{
+ acm_info_table_t *info_table;
+
+ printk(TBOOT_DETA"AC module header dump for %s:\n",
+ (mod_name == NULL) ? "?" : mod_name);
+
+ /* header */
+ printk(TBOOT_DETA"\t type: 0x%x ", hdr->module_type);
+ if ( hdr->module_type == ACM_TYPE_CHIPSET )
+ printk(TBOOT_DETA"(ACM_TYPE_CHIPSET)\n");
+ else
+ printk(TBOOT_INFO"(unknown)\n");
+ printk(TBOOT_DETA"\t subtype: 0x%x ", hdr->module_subtype);
+ if ( hdr->module_subtype == ACM_SUBTYPE_RESET )
+ printk(TBOOT_INFO"(execute at reset)\n");
+ else if ( hdr->module_subtype == 0 )
+ printk(TBOOT_INFO"\n");
+ else
+ printk(TBOOT_INFO"(unknown)\n");
+ printk(TBOOT_DETA"\t length: 0x%x (%u)\n", hdr->header_len, hdr->header_len);
+ printk(TBOOT_DETA"\t version: %u\n", hdr->header_ver);
+ printk(TBOOT_DETA"\t chipset_id: 0x%x\n", (uint32_t)hdr->chipset_id);
+ printk(TBOOT_DETA"\t flags: 0x%x\n", (uint32_t)hdr->flags._raw);
+ printk(TBOOT_DETA"\t\t pre_production: %d\n", (int)hdr->flags.pre_production);
+ printk(TBOOT_DETA"\t\t debug_signed: %d\n", (int)hdr->flags.debug_signed);
+ printk(TBOOT_DETA"\t vendor: 0x%x\n", hdr->module_vendor);
+ printk(TBOOT_DETA"\t date: 0x%08x\n", hdr->date);
+ printk(TBOOT_DETA"\t size*4: 0x%x (%u)\n", hdr->size*4, hdr->size*4);
+ printk(TBOOT_DETA"\t txt_svn: 0x%08x\n", hdr->txt_svn);
+ printk(TBOOT_DETA"\t se_svn: 0x%08x\n", hdr->se_svn);
+ printk(TBOOT_DETA"\t code_control: 0x%x\n", hdr->code_control);
+ printk(TBOOT_DETA"\t entry point: 0x%08x:%08x\n", hdr->seg_sel,
+ hdr->entry_point);
+ printk(TBOOT_DETA"\t scratch_size: 0x%x (%u)\n", hdr->scratch_size,
+ hdr->scratch_size);
+
+ /* info table */
+ printk(TBOOT_DETA"\t info_table:\n");
+ info_table = get_acmod_info_table(hdr);
+ if ( info_table == NULL ) {
+ printk(TBOOT_ERR"\t\t <invalid>\n");
+ return;
+ }
+ printk(TBOOT_DETA"\t\t uuid: "); print_uuid(&info_table->uuid);
+ printk(TBOOT_DETA"\n");
+ if ( are_uuids_equal(&(info_table->uuid), &((uuid_t)ACM_UUID_V3)) )
+ printk(TBOOT_DETA"\t\t ACM_UUID_V3\n");
+ else
+ printk(TBOOT_DETA"\t\t unknown\n");
+ printk(TBOOT_DETA"\t\t chipset_acm_type: 0x%x ",
+ (uint32_t)info_table->chipset_acm_type);
+ if ( info_table->chipset_acm_type == ACM_CHIPSET_TYPE_SINIT )
+ printk(TBOOT_DETA"(SINIT)\n");
+ else if ( info_table->chipset_acm_type == ACM_CHIPSET_TYPE_BIOS )
+ printk(TBOOT_DETA"(BIOS)\n");
+ else
+ printk(TBOOT_DETA"(unknown)\n");
+ printk(TBOOT_DETA"\t\t version: %u\n", (uint32_t)info_table->version);
+ printk(TBOOT_DETA"\t\t length: 0x%x (%u)\n", (uint32_t)info_table->length,
+ (uint32_t)info_table->length);
+ printk(TBOOT_DETA"\t\t chipset_id_list: 0x%x\n", info_table->chipset_id_list);
+ printk(TBOOT_DETA"\t\t os_sinit_data_ver: 0x%x\n", info_table->os_sinit_data_ver);
+ printk(TBOOT_DETA"\t\t min_mle_hdr_ver: 0x%08x\n", info_table->min_mle_hdr_ver);
+ print_txt_caps("\t\t ", info_table->capabilities);
+ printk(TBOOT_DETA"\t\t acm_ver: %u\n", (uint32_t)info_table->acm_ver);
+
+ /* chipset list */
+ printk(TBOOT_DETA"\t chipset list:\n");
+ acm_chipset_id_list_t *chipset_id_list = get_acmod_chipset_list(hdr);
+ if ( chipset_id_list == NULL ) {
+ printk(TBOOT_ERR"\t\t <invalid>\n");
+ return;
+ }
+ printk(TBOOT_DETA"\t\t count: %u\n", chipset_id_list->count);
+ for ( unsigned int i = 0; i < chipset_id_list->count; i++ ) {
+ printk(TBOOT_DETA"\t\t entry %u:\n", i);
+ acm_chipset_id_t *chipset_id = &(chipset_id_list->chipset_ids[i]);
+ printk(TBOOT_DETA"\t\t flags: 0x%x\n", chipset_id->flags);
+ printk(TBOOT_DETA"\t\t vendor_id: 0x%x\n", (uint32_t)chipset_id->vendor_id);
+ printk(TBOOT_DETA"\t\t device_id: 0x%x\n", (uint32_t)chipset_id->device_id);
+ printk(TBOOT_DETA"\t\t revision_id: 0x%x\n",
+ (uint32_t)chipset_id->revision_id);
+ printk(TBOOT_DETA"\t\t extended_id: 0x%x\n", chipset_id->extended_id);
+ }
+
+ if ( info_table->version >= 4 ) {
+ /* processor list */
+ printk(TBOOT_DETA"\t processor list:\n");
+ acm_processor_id_list_t *proc_id_list = get_acmod_processor_list(hdr);
+ if ( proc_id_list == NULL ) {
+ printk(TBOOT_ERR"\t\t <invalid>\n");
+ return;
+ }
+ printk(TBOOT_DETA"\t\t count: %u\n", proc_id_list->count);
+ for ( unsigned int i = 0; i < proc_id_list->count; i++ ) {
+ printk(TBOOT_DETA"\t\t entry %u:\n", i);
+ acm_processor_id_t *proc_id = &(proc_id_list->processor_ids[i]);
+ printk(TBOOT_DETA"\t\t fms: 0x%x\n", proc_id->fms);
+ printk(TBOOT_DETA"\t\t fms_mask: 0x%x\n", proc_id->fms_mask);
+ printk(TBOOT_DETA"\t\t platform_id: 0x%Lx\n", (unsigned long long)proc_id->platform_id);
+ printk(TBOOT_DETA"\t\t platform_mask: 0x%Lx\n", (unsigned long long)proc_id->platform_mask);
+ }
+ }
+
+ if ( info_table->version >= 5 ){
+ /* tpm infor list */
+ printk(TBOOT_DETA"\t TPM info list:\n");
+ tpm_info_list_t *info_list = get_tpm_info_list(hdr);
+ if ( info_list == NULL ) {
+ printk(TBOOT_ERR"\t\t <invalid>\n");
+ return;
+ }
+ printk(TBOOT_DETA"\t\t TPM capability:\n");
+ printk(TBOOT_DETA"\t\t ext_policy: 0x%x\n", info_list->capabilities.ext_policy);
+ printk(TBOOT_DETA"\t\t tpm_family : 0x%x\n", info_list->capabilities.tpm_family);
+ printk(TBOOT_DETA"\t\t tpm_nv_index_set : 0x%x\n", info_list->capabilities.tpm_nv_index_set);
+ printk(TBOOT_DETA"\t\t alg count: %u\n", info_list->count);
+ for ( unsigned int i = 0; i < info_list->count; i++ ) {
+ printk(TBOOT_DETA"\t\t alg_id: 0x%x\n", info_list->alg_id[i]);
+ }
+ }
+}
+
+uint32_t get_supported_os_sinit_data_ver(const acm_hdr_t* hdr)
+{
+ /* assumes that it passed is_sinit_acmod() */
+
+ acm_info_table_t *info_table = get_acmod_info_table(hdr);
+ if ( info_table == NULL )
+ return 0;
+
+ return info_table->os_sinit_data_ver;
+}
+
+txt_caps_t get_sinit_capabilities(const acm_hdr_t* hdr)
+{
+ /* assumes that it passed is_sinit_acmod() */
+
+ acm_info_table_t *info_table = get_acmod_info_table(hdr);
+ if ( info_table == NULL || info_table->version < 3 )
+ return (txt_caps_t){ 0 };
+
+ return info_table->capabilities;
+}
+
+static bool is_acmod(const void *acmod_base, uint32_t acmod_size, uint8_t *type, bool quiet)
+{
+ acm_hdr_t *acm_hdr = (acm_hdr_t *)acmod_base;
+
+ /* first check size */
+ if ( acmod_size < sizeof(acm_hdr_t) ) {
+ if ( !quiet )
+ printk(TBOOT_ERR"\t ACM size is too small: acmod_size=%x,"
+ " sizeof(acm_hdr)=%x\n", acmod_size,
+ (uint32_t)sizeof(acm_hdr) );
+ return false;
+ }
+
+ /* then check overflow */
+ if ( multiply_overflow_u32(acm_hdr->size, 4) ) {
+ if ( !quiet )
+ printk(TBOOT_ERR"\t ACM header size in bytes overflows\n");
+ return false;
+ }
+
+ /* then check size equivalency */
+ if ( acmod_size != acm_hdr->size * 4 ) {
+ if ( !quiet )
+ printk(TBOOT_ERR"\t ACM size is too small: acmod_size=%x,"
+ " acm_hdr->size*4=%x\n", acmod_size, acm_hdr->size*4);
+ return false;
+ }
+
+ /* then check type and vendor */
+ if ( (acm_hdr->module_type != ACM_TYPE_CHIPSET) ||
+ (acm_hdr->module_vendor != ACM_VENDOR_INTEL) ) {
+ if ( !quiet )
+ printk(TBOOT_ERR"\t ACM type/vendor mismatch: module_type=%x,"
+ " module_vendor=%x\n", acm_hdr->module_type,
+ acm_hdr->module_vendor);
+ return false;
+ }
+
+ acm_info_table_t *info_table = get_acmod_info_table(acm_hdr);
+ if ( info_table == NULL )
+ return false;
+
+ /* check if ACM UUID is present */
+ if ( !are_uuids_equal(&(info_table->uuid), &((uuid_t)ACM_UUID_V3)) ) {
+ if ( !quiet ) {
+ printk(TBOOT_ERR"\t unknown UUID: "); print_uuid(&info_table->uuid);
+ printk(TBOOT_ERR"\n");
+ }
+ return false;
+ }
+
+ if ( type != NULL )
+ *type = info_table->chipset_acm_type;
+
+ if ( info_table->version < 3 ) {
+ if ( !quiet )
+ printk(TBOOT_ERR"\t ACM info_table version unsupported (%u)\n",
+ (uint32_t)info_table->version);
+ return false;
+ }
+ /* there is forward compatibility, so this is just a warning */
+ else if ( info_table->version > 5 ) {
+ if ( !quiet )
+ printk(TBOOT_WARN"\t ACM info_table version mismatch (%u)\n",
+ (uint32_t)info_table->version);
+ }
+
+ return true;
+}
+
+bool is_racm_acmod(const void *acmod_base, uint32_t acmod_size, bool quiet)
+{
+ uint8_t type;
+
+ if ( !is_acmod(acmod_base, acmod_size, &type, quiet) )
+ return false;
+
+ if ( type != ACM_CHIPSET_TYPE_BIOS_REVOC &&
+ type != ACM_CHIPSET_TYPE_SINIT_REVOC ) {
+ printk(TBOOT_ERR"ACM is not an revocation ACM (%x)\n", type);
+ return false;
+ }
+
+ if ( acmod_size != 0x8000 && acmod_size != 0x10000 ) {
+ printk(TBOOT_ERR"ACM is not an RACM, bad size (0x%x)\n", acmod_size);
+ return false;
+ }
+
+ return true;
+}
+
+bool is_sinit_acmod(const void *acmod_base, uint32_t acmod_size, bool quiet)
+{
+ uint8_t type;
+
+ if ( !is_acmod(acmod_base, acmod_size, &type, quiet) )
+ return false;
+
+ if ( type != ACM_CHIPSET_TYPE_SINIT ) {
+ printk(TBOOT_ERR"ACM is not an SINIT ACM (%x)\n", type);
+ return false;
+ }
+
+ return true;
+}
+
+bool does_acmod_match_platform(const acm_hdr_t* hdr)
+{
+ /* used to ensure we don't print chipset/proc info for each module */
+ static bool printed_host_info;
+
+ /* this fn assumes that the ACM has already passed the is_acmod() checks */
+
+ /* get chipset fusing, device, and vendor id info */
+ txt_didvid_t didvid;
+ didvid._raw = read_pub_config_reg(TXTCR_DIDVID);
+ txt_ver_fsbif_qpiif_t ver;
+ ver._raw = read_pub_config_reg(TXTCR_VER_FSBIF);
+ if ( (ver._raw & 0xffffffff) == 0xffffffff ||
+ (ver._raw & 0xffffffff) == 0x00 ) /* need to use VER.QPIIF */
+ ver._raw = read_pub_config_reg(TXTCR_VER_QPIIF);
+ if ( !printed_host_info ) {
+ printk(TBOOT_DETA"chipset production fused: %x\n", ver.prod_fused );
+ printk(TBOOT_DETA"chipset ids: vendor: 0x%x, device: 0x%x, revision: 0x%x\n",
+ didvid.vendor_id, didvid.device_id, didvid.revision_id);
+ }
+
+ /* get processor family/model/stepping and platform ID */
+ uint64_t platform_id;
+ uint32_t fms = cpuid_eax(1);
+ platform_id = rdmsr(MSR_IA32_PLATFORM_ID);
+ if ( !printed_host_info ) {
+ printk(TBOOT_DETA"processor family/model/stepping: 0x%x\n", fms );
+ printk(TBOOT_DETA"platform id: 0x%Lx\n", (unsigned long long)platform_id);
+ }
+ printed_host_info = true;
+
+ /*
+ * check if chipset fusing is same
+ */
+ if ( ver.prod_fused != !hdr->flags.debug_signed ) {
+ printk(TBOOT_ERR"\t production/debug mismatch between chipset and ACM\n");
+ return false;
+ }
+
+ /*
+ * check if chipset vendor/device/revision IDs match
+ */
+ acm_chipset_id_list_t *chipset_id_list = get_acmod_chipset_list(hdr);
+ if ( chipset_id_list == NULL )
+ return false;
+
+ printk(TBOOT_DETA"\t %x ACM chipset id entries:\n", chipset_id_list->count);
+ unsigned int i;
+ for ( i = 0; i < chipset_id_list->count; i++ ) {
+ acm_chipset_id_t *chipset_id = &(chipset_id_list->chipset_ids[i]);
+ printk(TBOOT_DETA"\t vendor: 0x%x, device: 0x%x, flags: 0x%x, "
+ "revision: 0x%x, extended: 0x%x\n",
+ (uint32_t)chipset_id->vendor_id,
+ (uint32_t)chipset_id->device_id, chipset_id->flags,
+ (uint32_t)chipset_id->revision_id, chipset_id->extended_id);
+
+ if ( (didvid.vendor_id == chipset_id->vendor_id ) &&
+ (didvid.device_id == chipset_id->device_id ) &&
+ ( ( ( (chipset_id->flags & 0x1) == 0) &&
+ (didvid.revision_id == chipset_id->revision_id) ) ||
+ ( ( (chipset_id->flags & 0x1) == 1) &&
+ ( (didvid.revision_id & chipset_id->revision_id) != 0 ) ) ) )
+ break;
+ }
+ if ( i >= chipset_id_list->count ) {
+ printk(TBOOT_ERR"\t chipset id mismatch\n");
+ return false;
+ }
+
+ /*
+ * check if processor family/model/stepping and platform IDs match
+ */
+ acm_info_table_t *info_table = get_acmod_info_table(hdr);
+ if ( info_table == NULL )
+ return false;
+
+ if ( info_table->version >= 4 ) {
+ acm_processor_id_list_t *proc_id_list = get_acmod_processor_list(hdr);
+ if ( proc_id_list == NULL )
+ return false;
+
+ printk(TBOOT_DETA"\t %x ACM processor id entries:\n", proc_id_list->count);
+ for ( i = 0; i < proc_id_list->count; i++ ) {
+ acm_processor_id_t *proc_id = &(proc_id_list->processor_ids[i]);
+ printk(TBOOT_DETA"\t fms: 0x%x, fms_mask: 0x%x, platform_id: 0x%Lx, "
+ "platform_mask: 0x%Lx\n",
+ proc_id->fms, proc_id->fms_mask,
+ (unsigned long long)proc_id->platform_id,
+ (unsigned long long)proc_id->platform_mask);
+
+ if ( (proc_id->fms == (fms & proc_id->fms_mask)) &&
+ (proc_id->platform_id == (platform_id & proc_id->platform_mask))
+ )
+ break;
+ }
+ if ( i >= proc_id_list->count ) {
+ printk(TBOOT_ERR"\t processor mismatch\n");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+#ifndef IS_INCLUDED
+acm_hdr_t *get_bios_sinit(const void *sinit_region_base)
+{
+ txt_heap_t *txt_heap = get_txt_heap();
+ bios_data_t *bios_data = get_bios_data_start(txt_heap);
+
+ if ( bios_data->bios_sinit_size == 0 )
+ return NULL;
+
+ /* BIOS has loaded an SINIT module, so verify that it is valid */
+ printk(TBOOT_INFO"BIOS has already loaded an SINIT module\n");
+
+ /* is it a valid SINIT module? */
+ if ( !is_sinit_acmod(sinit_region_base, bios_data->bios_sinit_size, false) ||
+ !does_acmod_match_platform((acm_hdr_t *)sinit_region_base) )
+ return NULL;
+
+ return (acm_hdr_t *)sinit_region_base;
+}
+
+static void *alloc_racm_region(uint32_t size)
+{
+ /* TODO: find a real unused memory place through mbi */
+ return (void *)(unsigned long long)(0x2000000 + size - size); /* 32M */
+}
+
+acm_hdr_t *copy_racm(const acm_hdr_t *racm)
+{
+ /* find a 32KB aligned memory */
+ uint32_t racm_region_size = racm->size*4;
+ void *racm_region_base = alloc_racm_region(racm_region_size);
+ printk(TBOOT_DETA"RACM.BASE: %p\n", racm_region_base);
+ printk(TBOOT_DETA"RACM.SIZE: 0x%x (%u)\n", racm_region_size, racm_region_size);
+
+ /* copy it there */
+ memcpy(racm_region_base, racm, racm->size*4);
+
+ printk(TBOOT_DETA"copied RACM (size=%x) to %p\n", racm->size*4,
+ racm_region_base);
+
+ return (acm_hdr_t *)racm_region_base;
+}
+
+acm_hdr_t *copy_sinit(const acm_hdr_t *sinit)
+{
+ /* get BIOS-reserved region from TXT.SINIT.BASE config reg */
+ void *sinit_region_base =
+ (void*)(unsigned long long)read_pub_config_reg(TXTCR_SINIT_BASE);
+ uint32_t sinit_region_size = (uint32_t)read_pub_config_reg(TXTCR_SINIT_SIZE);
+ printk(TBOOT_DETA"TXT.SINIT.BASE: %p\n", sinit_region_base);
+ printk(TBOOT_DETA"TXT.SINIT.SIZE: 0x%x (%u)\n", sinit_region_size, sinit_region_size);
+
+ /*
+ * check if BIOS already loaded an SINIT module there
+ */
+ acm_hdr_t *bios_sinit = get_bios_sinit(sinit_region_base);
+ if ( bios_sinit != NULL ) {
+ /* no other SINIT was provided so must use one BIOS provided */
+ if ( sinit == NULL ) {
+ printk(TBOOT_WARN"no SINIT provided by bootloader; using BIOS SINIT\n");
+ return bios_sinit;
+ }
+
+ /* is it newer than the one we've been provided? */
+ if ( bios_sinit->date >= sinit->date ) {
+ printk(TBOOT_INFO"BIOS-provided SINIT is newer, so using it\n");
+ return bios_sinit; /* yes */
+ }
+ else
+ printk(TBOOT_INFO"BIOS-provided SINIT is older: date=%x\n", bios_sinit->date);
+ }
+ /* our SINIT is newer than BIOS's (or BIOS did not have one) */
+
+ /* BIOS SINIT not present or not valid and none provided */
+ if ( sinit == NULL )
+ return NULL;
+
+ /* overflow? */
+ if ( multiply_overflow_u32(sinit->size, 4) ) {
+ printk(TBOOT_ERR"sinit size in bytes overflows\n");
+ return NULL;
+ }
+
+ /* make sure our SINIT fits in the reserved region */
+ if ( (sinit->size * 4) > sinit_region_size ) {
+ printk(TBOOT_ERR"BIOS-reserved SINIT size (%x) is too small for loaded "
+ "SINIT (%x)\n", sinit_region_size, sinit->size*4);
+ return NULL;
+ }
+
+ /* copy it there */
+ memcpy(sinit_region_base, sinit, sinit->size*4);
+
+ printk(TBOOT_DETA"copied SINIT (size=%x) to %p\n", sinit->size*4,
+ sinit_region_base);
+
+ return (acm_hdr_t *)sinit_region_base;
+}
+#endif /* IS_INCLUDED */
+
+bool verify_racm(const acm_hdr_t *acm_hdr)
+{
+ getsec_parameters_t params;
+ uint32_t size;
+
+ /* assumes this already passed is_acmod() test */
+
+ size = acm_hdr->size * 4; /* hdr size is in dwords, we want bytes */
+
+ /*
+ * AC mod must start on 4k page boundary
+ */
+
+ if ( (unsigned long long)acm_hdr & 0xfff ) {
+ printk(TBOOT_ERR"AC mod base not 4K aligned (%p)\n", acm_hdr);
+ return false;
+ }
+ printk(TBOOT_INFO"AC mod base alignment OK\n");
+
+ /* AC mod size must:
+ * - be multiple of 64
+ * - greater than ???
+ * - less than max supported size for this processor
+ */
+
+ if ( (size == 0) || ((size % 64) != 0) ) {
+ printk(TBOOT_ERR"AC mod size %x bogus\n", size);
+ return false;
+ }
+
+ if ( !get_parameters(&params) ) {
+ printk(TBOOT_ERR"get_parameters() failed\n");
+ return false;
+ }
+
+ if ( size > params.acm_max_size ) {
+ printk(TBOOT_ERR"AC mod size too large: %x (max=%x)\n", size,
+ params.acm_max_size);
+ return false;
+ }
+
+ printk(TBOOT_INFO"AC mod size OK\n");
+
+ /*
+ * perform checks on AC mod structure
+ */
+
+ /* print it for debugging */
+ print_acm_hdr(acm_hdr, "RACM");
+
+ /* entry point is offset from base addr so make sure it is within module */
+ if ( acm_hdr->entry_point >= size ) {
+ printk(TBOOT_ERR"AC mod entry (%08x) >= AC mod size (%08x)\n",
+ acm_hdr->entry_point, size);
+ return false;
+ }
+
+ /* overflow? */
+ if ( plus_overflow_u32(acm_hdr->seg_sel, 8) ) {
+ printk(TBOOT_ERR"seg_sel plus 8 overflows\n");
+ return false;
+ }
+
+ if ( !acm_hdr->seg_sel || /* invalid selector */
+ (acm_hdr->seg_sel & 0x07) || /* LDT, PL!=0 */
+ (acm_hdr->seg_sel + 8 > acm_hdr->gdt_limit) ) {
+ printk(TBOOT_ERR"AC mod selector [%04x] bogus\n", acm_hdr->seg_sel);
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * Do some AC module sanity checks because any violations will cause
+ * an TXT.RESET. Instead detect these, print a desriptive message,
+ * and skip SENTER/ENTERACCS
+ */
+#ifndef IS_INCLUDED /* defined in utils/acminfo.c */
+void verify_IA32_se_svn_status(const acm_hdr_t *acm_hdr)
+{
+
+ printk(TBOOT_INFO"SGX:verify_IA32_se_svn_status is called\n");
+
+ //check if SGX is enabled by cpuid with ax=7, cx=0
+ if ((cpuid_ebx1(7,0) & 0x00000004) == 0){
+ printk(TBOOT_ERR"SGX is not enabled, cpuid.ebx: 0x%x\n", cpuid_ebx1(7,0));
+ return;
+ }
+ printk(TBOOT_INFO"SGX is enabled, cpuid.ebx:0x%x\n", cpuid_ebx1(7,0));
+ printk(TBOOT_INFO"Comparing se_svn with ACM Header se_svn\n");
+
+ if (((rdmsr(MSR_IA32_SE_SVN_STATUS)>>16) & 0xff) != acm_hdr->se_svn) {
+ printk(TBOOT_INFO"se_svn is not equal to ACM se_svn\n");
+ if (!g_tpm->nv_write(g_tpm, 0, g_tpm->sgx_svn_index, 0, (uint8_t *)&(acm_hdr->se_svn), 1))
+ printk(TBOOT_ERR"Write sgx_svn_index 0x%x failed. \n", g_tpm->sgx_svn_index);
+ else
+ printk(TBOOT_INFO"Write sgx_svn_index with 0x%x successful.\n", acm_hdr->se_svn);
+
+ if ((rdmsr(MSR_IA32_SE_SVN_STATUS) & 0X00000001) !=0) /* reset platform */
+ // printk(TBOOT_INFO"SGX:A reset is required in this boot\n");
+ outb(0xcf9, 0x06);
+ }
+ else
+ printk(TBOOT_INFO"se_svn is equal to ACM se_svn\n");
+
+}
+
+
+bool verify_acmod(const acm_hdr_t *acm_hdr)
+{
+ getsec_parameters_t params;
+ uint32_t size;
+
+ /* assumes this already passed is_acmod() test */
+
+ size = acm_hdr->size * 4; /* hdr size is in dwords, we want bytes */
+
+ /*
+ * AC mod must start on 4k page boundary
+ */
+
+ if ( (unsigned long long)acm_hdr & 0xfff ) {
+ printk(TBOOT_ERR"AC mod base not 4K aligned (%p)\n", acm_hdr);
+ return false;
+ }
+ printk(TBOOT_INFO"AC mod base alignment OK\n");
+
+ /* AC mod size must:
+ * - be multiple of 64
+ * - greater than ???
+ * - less than max supported size for this processor
+ */
+
+ if ( (size == 0) || ((size % 64) != 0) ) {
+ printk(TBOOT_ERR"AC mod size %x bogus\n", size);
+ return false;
+ }
+
+ if ( !get_parameters(&params) ) {
+ printk(TBOOT_ERR"get_parameters() failed\n");
+ return false;
+ }
+
+ if ( size > params.acm_max_size ) {
+ printk(TBOOT_ERR"AC mod size too large: %x (max=%x)\n", size,
+ params.acm_max_size);
+ return false;
+ }
+
+ printk(TBOOT_INFO"AC mod size OK\n");
+
+ /*
+ * perform checks on AC mod structure
+ */
+
+ /* print it for debugging */
+ print_acm_hdr(acm_hdr, "SINIT");
+
+ /* verify SE enablement status */
+ verify_IA32_se_svn_status(acm_hdr);
+
+ /* entry point is offset from base addr so make sure it is within module */
+ if ( acm_hdr->entry_point >= size ) {
+ printk(TBOOT_ERR"AC mod entry (%08x) >= AC mod size (%08x)\n",
+ acm_hdr->entry_point, size);
+ return false;
+ }
+
+ /* overflow? */
+ if ( plus_overflow_u32(acm_hdr->seg_sel, 8) ) {
+ printk(TBOOT_ERR"seg_sel plus 8 overflows\n");
+ return false;
+ }
+
+ if ( !acm_hdr->seg_sel || /* invalid selector */
+ (acm_hdr->seg_sel & 0x07) || /* LDT, PL!=0 */
+ (acm_hdr->seg_sel + 8 > acm_hdr->gdt_limit) ) {
+ printk(TBOOT_ERR"AC mod selector [%04x] bogus\n", acm_hdr->seg_sel);
+ return false;
+ }
+
+ /*
+ * check for compatibility with this MLE
+ */
+
+ acm_info_table_t *info_table = get_acmod_info_table(acm_hdr);
+ if ( info_table == NULL )
+ return false;
+
+ /* check MLE header versions */
+ if ( info_table->min_mle_hdr_ver > MLE_HDR_VER ) {
+ printk(TBOOT_ERR"AC mod requires a newer MLE (0x%08x)\n",
+ info_table->min_mle_hdr_ver);
+ return false;
+ }
+
+ /* check capabilities */
+ /* we need to match one of rlp_wake_{getsec, monitor} */
+ txt_caps_t caps_mask = { 0 };
+ caps_mask.rlp_wake_getsec = caps_mask.rlp_wake_monitor = 1;
+
+ if ( ( ( MLE_HDR_CAPS & caps_mask._raw ) &
+ ( info_table->capabilities._raw & caps_mask._raw) ) == 0 ) {
+ printk(TBOOT_ERR"SINIT and MLE not support compatible RLP wake mechanisms\n");
+ return false;
+ }
+ /* we also expect ecx_pgtbl to be set */
+ if ( !info_table->capabilities.ecx_pgtbl ) {
+ printk(TBOOT_ERR"SINIT does not support launch with MLE pagetable in ECX\n");
+ /* TODO when SINIT ready
+ * return false;
+ */
+ }
+
+ /* check for version of OS to SINIT data */
+ /* we don't support old versions */
+ if ( info_table->os_sinit_data_ver < MIN_OS_SINIT_DATA_VER ) {
+ printk(TBOOT_ERR"SINIT's os_sinit_data version unsupported (%u)\n",
+ info_table->os_sinit_data_ver);
+ return false;
+ }
+ /* only warn if SINIT supports more recent version than us */
+ else if ( info_table->os_sinit_data_ver > MAX_OS_SINIT_DATA_VER ) {
+ printk(TBOOT_WARN"SINIT's os_sinit_data version unsupported (%u)\n",
+ info_table->os_sinit_data_ver);
+ }
+
+ return true;
+}
+#endif /* IS_INCLUDED */
+/*
+ * Local variables:
+ * mode: C
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */