/* * txt.c: Intel(r) TXT support functions, including initiating measured * launch, post-launch, AP wakeup, etc. * * 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. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* counter timeout for waiting for all APs to enter wait-for-sipi */ #define AP_WFS_TIMEOUT 0x01000000 /* MLE/kernel shared data page (in boot.S) */ void apply_policy(tb_error_t error); void print_event(const tpm12_pcr_event_t *evt); void print_event_2(void *evt, uint16_t alg); __data struct acpi_rsdp g_rsdp; /* * this is the structure whose addr we'll put in TXT heap and * it needs to be within the MLE pages, so force it to the .text section. * It is filled in at runtime with set values that don't change and * are based of the relocated fixed physical base address of the TBOOT * EFI RT memory region. */ __text mle_hdr_t g_mle_hdr = { uuid : MLE_HDR_UUID, length : sizeof(mle_hdr_t), version : MLE_HDR_VER, entry_point : 0, /* Linear virt. offset to the EP, used by ACM */ first_valid_page : 0, mle_start_off : 0, /* Offset from TBOOT base, used by SW */ mle_end_off : 0, /* Offset from TBOOT base, used by SW */ capabilities : { MLE_HDR_CAPS }, cmdline_start_off : 0, /* Offset from TBOOT base, used by SW */ cmdline_end_off : 0 /* Offset from TBOOT base, used by SW */ }; /* * counts of APs going into wait-for-sipi */ /* count of APs in WAIT-FOR-SIPI */ atomic_t ap_wfs_count; static __data uint8_t *g_mle_pt; __data uint32_t g_using_da = 0; static __data event_log_container_t *g_elog = NULL; static __data heap_event_log_ptr_elt2_t *g_elog_2 = NULL; static void print_file_info(void) { printk(TBOOT_DETA"file addresses:\n"); printk(TBOOT_DETA"\t RTMEM start=%p\n", g_rtmem_base); printk(TBOOT_DETA"\t RTMEM end=%p\n", g_rtmem_base + g_image_size + TBOOT_RTMEM_SIZE); printk(TBOOT_DETA"\t IMAGE start=%p\n", g_image_base); printk(TBOOT_DETA"\t IMAGE end=%p\n", g_image_base + g_image_size); printk(TBOOT_DETA"\t MLE start=%p\n", g_text_base); printk(TBOOT_DETA"\t MLE end=%p\n", g_text_base + g_text_size); /*printk(TBOOT_DETA"\t &_post_launch_entry=%p\n", &_post_launch_entry); printk(TBOOT_DETA"\t &_txt_wakeup=%p\n", &_txt_wakeup);*/ printk(TBOOT_DETA"\t &g_mle_hdr=%p\n", &g_mle_hdr); } static void print_mle_hdr(const mle_hdr_t *mle_hdr) { printk(TBOOT_DETA"MLE header:\n"); printk(TBOOT_DETA"\t uuid="); print_uuid(&mle_hdr->uuid); printk(TBOOT_DETA"\n"); printk(TBOOT_DETA"\t length=%x\n", mle_hdr->length); printk(TBOOT_DETA"\t version=%08x\n", mle_hdr->version); printk(TBOOT_DETA"\t entry_point=%08x\n", mle_hdr->entry_point); printk(TBOOT_DETA"\t first_valid_page=%08x\n", mle_hdr->first_valid_page); printk(TBOOT_DETA"\t mle_start_off=%x\n", mle_hdr->mle_start_off); printk(TBOOT_DETA"\t mle_end_off=%x\n", mle_hdr->mle_end_off); printk(TBOOT_DETA"\t cmdline_start_off=%x\n", mle_hdr->cmdline_start_off); printk(TBOOT_DETA"\t cmdline_end_off=%x\n", mle_hdr->cmdline_end_off); print_txt_caps("\t ", mle_hdr->capabilities); } #if 0 static void print_mle_pagetable(void) { uint32_t mle_size, mle_off; void *pg_dir_ptr_tab, *pg_dir, *pg_tab; uint64_t *pte; int i = 0; mle_size = g_mle_hdr.mle_end_off - g_mle_hdr.mle_start_off; pg_dir_ptr_tab = g_mle_pt; pg_dir = pg_dir_ptr_tab + PAGE_SIZE; pg_tab = pg_dir + PAGE_SIZE; printk(TBOOT_DETA"MLE Page Tables:\n"); printk(" pg_dir_ptr_tab=%016llx pg_dir_ptr_tab[0]=%016llx pg_dir_ptr_tab[1]=%016llx\n", (uint64_t)pg_dir_ptr_tab, *(uint64_t *)pg_dir_ptr_tab, *(uint64_t *)(pg_dir_ptr_tab + 8)); printk(" pg_dir=%016llx pg_dir[0]=%016llx pg_dir[1]=%016llx\n", (uint64_t)pg_dir, *(uint64_t *)pg_dir, *(uint64_t *)(pg_dir + 8)); pte = pg_tab; mle_off = 0; printk(" pg_tab=%016llx\n", (uint64_t)pg_tab); for (i = 0; mle_off < mle_size; i++, pte++, mle_off += PAGE_SIZE) printk(" pte[%d]=%016llx\n", i, *pte); } #endif void txt_init_mle_header(void) { uint64_t ple; lea_reference(post_launch_entry, ple); g_mle_hdr.entry_point = (uint32_t)(ple - (uint64_t)g_text_base); g_mle_hdr.mle_start_off = (uint32_t)((uint64_t)g_text_base - (uint64_t)g_rtmem_base); g_mle_hdr.mle_end_off = (uint32_t)((uint64_t)g_text_base + (uint64_t)g_text_size - (uint64_t)g_rtmem_base); g_mle_hdr.cmdline_start_off = (uint32_t)((uint64_t)g_cmdline - (uint64_t)g_rtmem_base); g_mle_hdr.cmdline_end_off = (uint32_t)((uint64_t)g_cmdline + CMDLINE_SIZE - 1 - (uint64_t)g_rtmem_base); print_mle_hdr(&g_mle_hdr); } /* page dir/table entry is phys addr + P + R/W + PWT */ #define MAKE_PDTE(addr) (((uint64_t)(unsigned long long)(addr) & PAGE_MASK) | 0x01) /* we assume/know that our image is <2MB and thus fits w/in a single */ /* PT (512*4KB = 2MB) and thus fixed to 1 pg dir ptr and 1 pgdir and */ /* 1 ptable = 3 pages and just 1 loop loop for ptable MLE page table */ /* can only contain 4k pages */ /* pgdir ptr + pgdir + ptab = 3 */ bool txt_build_mle_pagetable(void) { uint32_t mle_start, mle_size; void *ptab_base; uint32_t ptab_size, mle_off; void *pg_dir_ptr_tab, *pg_dir, *pg_tab; uint64_t *pte; /* page tables start at the phys addr of the MLE base and cover MLE */ mle_start = g_mle_hdr.mle_start_off + (uint32_t)(uint64_t)g_rtmem_base; mle_size = g_mle_hdr.mle_end_off - g_mle_hdr.mle_start_off; /* place PTs in 3 page before the TBOOT image */ g_mle_pt = g_rtmem_base + TBOOT_PLEPT_SIZE; printk(TBOOT_DETA"MLE start=0x%x, end=0x%x, size=0x%x\n", mle_start, mle_start+mle_size, mle_size); if ( mle_size > 512*PAGE_SIZE ) { printk(TBOOT_ERR"MLE size too big for single page table\n"); return false; } /* should start on page boundary */ if ( mle_start & ~PAGE_MASK ) { printk(TBOOT_ERR"MLE start is not page-aligned\n"); return false; } /* place ptab_base below MLE */ ptab_size = TBOOT_MLEPT_SIZE; ptab_base = g_mle_pt; /* already zeroed */ printk(TBOOT_DETA"ptab_size=%x, ptab_base=%p\n", ptab_size, ptab_base); pg_dir_ptr_tab = ptab_base; pg_dir = pg_dir_ptr_tab + PAGE_SIZE; pg_tab = pg_dir + PAGE_SIZE; /* only use first entry in page dir ptr table */ *(uint64_t *)pg_dir_ptr_tab = MAKE_PDTE(pg_dir); /* only use first entry in page dir */ *(uint64_t *)pg_dir = MAKE_PDTE(pg_tab); pte = pg_tab; mle_off = 0; do { *pte = MAKE_PDTE(mle_start + mle_off); pte++; mle_off += PAGE_SIZE; } while ( mle_off < mle_size ); /* DEBUG print_mle_pagetable();*/ return true; } /* should be called after os_mle_data initialized */ static void *init_event_log(void) { os_mle_data_t *os_mle_data = get_os_mle_data_start(get_txt_heap()); g_elog = (event_log_container_t *)&os_mle_data->event_log_buffer; memcpy((void *)g_elog->signature, EVTLOG_SIGNATURE, sizeof(g_elog->signature)); g_elog->container_ver_major = EVTLOG_CNTNR_MAJOR_VER; g_elog->container_ver_minor = EVTLOG_CNTNR_MINOR_VER; g_elog->pcr_event_ver_major = EVTLOG_EVT_MAJOR_VER; g_elog->pcr_event_ver_minor = EVTLOG_EVT_MINOR_VER; g_elog->size = sizeof(os_mle_data->event_log_buffer); g_elog->pcr_events_offset = sizeof(*g_elog); g_elog->next_event_offset = sizeof(*g_elog); return (void *)g_elog; } static void init_evtlog_desc(heap_event_log_ptr_elt2_t *evt_log) { unsigned int i; os_mle_data_t *os_mle_data = get_os_mle_data_start(get_txt_heap()); switch (g_tpm->extpol) { case TB_EXTPOL_AGILE: for (i=0; icount; i++) { evt_log->event_log_descr[i].alg = g_tpm->algs_banks[i]; evt_log->event_log_descr[i].phys_addr = (uint64_t)(os_mle_data->event_log_buffer + i*4096); evt_log->event_log_descr[i].size = 4096; evt_log->event_log_descr[i].pcr_events_offset = 0; evt_log->event_log_descr[i].next_event_offset = 0; } break; case TB_EXTPOL_EMBEDDED: for (i=0; icount; i++) { evt_log->event_log_descr[i].alg = g_tpm->algs[i]; evt_log->event_log_descr[i].phys_addr = (uint64_t)(os_mle_data->event_log_buffer + i*4096); evt_log->event_log_descr[i].size = 4096; evt_log->event_log_descr[i].pcr_events_offset = 0; evt_log->event_log_descr[i].next_event_offset = 0; } break; case TB_EXTPOL_FIXED: evt_log->event_log_descr[0].alg = g_tpm->cur_alg; evt_log->event_log_descr[0].phys_addr = (uint64_t)os_mle_data->event_log_buffer; evt_log->event_log_descr[0].size = 4096; evt_log->event_log_descr[0].pcr_events_offset = 0; evt_log->event_log_descr[0].next_event_offset = 0; break; default: return; } } static void init_os_sinit_ext_data(heap_ext_data_element_t* elts) { heap_ext_data_element_t* elt = elts; heap_event_log_ptr_elt_t *evt_log; if ( g_tpm->major == TPM12_VER_MAJOR ) { evt_log = (heap_event_log_ptr_elt_t *)elt->data; evt_log->event_log_phys_addr = (uint64_t)init_event_log(); elt->type = HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR; elt->size = sizeof(*elt) + sizeof(*evt_log); } else if ( g_tpm->major == TPM20_VER_MAJOR ) { g_elog_2 = (heap_event_log_ptr_elt2_t *)elt->data; if ( g_tpm->extpol == TB_EXTPOL_AGILE ) g_elog_2->count = g_tpm->banks; else if ( g_tpm->extpol == TB_EXTPOL_EMBEDDED ) g_elog_2->count = g_tpm->alg_count; else g_elog_2->count = 1; init_evtlog_desc(g_elog_2); elt->type = HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR_2; elt->size = sizeof(*elt) + sizeof(u32) + g_elog_2->count * sizeof(heap_event_log_descr_t); } elt = (void *)elt + elt->size; elt->type = HEAP_EXTDATA_TYPE_END; elt->size = sizeof(*elt); } /* * sets up TXT heap */ static txt_heap_t *init_txt_heap(void *ptab_base, acm_hdr_t *sinit) { txt_heap_t *txt_heap; txt_caps_t sinit_caps; txt_caps_t caps_mask = { 0 }; uint64_t *size; uint64_t min_lo_ram, max_lo_ram, min_hi_ram, max_hi_ram; const efi_file_t *lcp_file; struct acpi_rsdp *rsdp; txt_heap = get_txt_heap(); /* * BIOS data already setup by BIOS */ if ( !verify_txt_heap(txt_heap, true) ) return NULL; /* * OS/loader to MLE data */ os_mle_data_t *os_mle_data = get_os_mle_data_start(txt_heap); size = (uint64_t *)((uint64_t)os_mle_data - sizeof(uint64_t)); *size = sizeof(*os_mle_data) + sizeof(uint64_t); memset(os_mle_data, 0, sizeof(*os_mle_data)); os_mle_data->version = 3; os_mle_data->saved_misc_enable_msr = rdmsr(MSR_IA32_MISC_ENABLE); /* * OS/loader to SINIT data */ /* check sinit supported os_sinit_data version */ uint32_t version = get_supported_os_sinit_data_ver(sinit); if ( version < MIN_OS_SINIT_DATA_VER ) { printk(TBOOT_ERR"unsupported OS to SINIT data version(%u) in sinit\n", version); return NULL; } if ( version > MAX_OS_SINIT_DATA_VER ) version = MAX_OS_SINIT_DATA_VER; os_sinit_data_t *os_sinit_data = get_os_sinit_data_start(txt_heap); size = (uint64_t *)((uint64_t)os_sinit_data - sizeof(uint64_t)); *size = calc_os_sinit_data_size(version); memset(os_sinit_data, 0, *size); os_sinit_data->version = version; /* this is phys addr */ os_sinit_data->mle_ptab = (uint64_t)ptab_base; os_sinit_data->mle_size = g_mle_hdr.mle_end_off - g_mle_hdr.mle_start_off; /* this is linear addr (offset from MLE base) of mle header */ os_sinit_data->mle_hdr_base = (uint64_t)&g_mle_hdr - (uint64_t)g_text_base; /* VT-d PMRs */ if ( !efi_get_ram_ranges(&min_lo_ram, &max_lo_ram, &min_hi_ram, &max_hi_ram) ) return NULL; set_vtd_pmrs(os_sinit_data, min_lo_ram, max_lo_ram, min_hi_ram, max_hi_ram); /* LCP owner policy data */ lcp_file = efi_get_lcp(); if (lcp_file) { /* copy to heap */ if ( lcp_file->size > sizeof(os_mle_data->lcp_po_data) ) { printk(TBOOT_ERR"LCP owner policy data file is too large (%u)\n", lcp_file->size); return NULL; } memcpy(os_mle_data->lcp_po_data, lcp_file->u.buffer, lcp_file->size); os_sinit_data->lcp_po_base = (unsigned long long)&os_mle_data->lcp_po_data; os_sinit_data->lcp_po_size = lcp_file->size; } sinit_caps = get_sinit_capabilities(sinit); caps_mask.rlp_wake_getsec = 1; caps_mask.rlp_wake_monitor = 1; caps_mask.pcr_map_da = 1; os_sinit_data->capabilities._raw = MLE_HDR_CAPS & ~caps_mask._raw; if ( sinit_caps.rlp_wake_monitor ) os_sinit_data->capabilities.rlp_wake_monitor = 1; else if ( sinit_caps.rlp_wake_getsec ) os_sinit_data->capabilities.rlp_wake_getsec = 1; else { /* should have been detected in verify_acmod() */ printk(TBOOT_ERR"SINIT capabilities are incompatible (0x%x)\n", sinit_caps._raw); return NULL; } /* capabilities : require MLE pagetable in ECX on launch */ /* TODO: when SINIT ready * os_sinit_data->capabilities.ecx_pgtbl = 1; */ os_sinit_data->capabilities.ecx_pgtbl = 0; /* Always true for us: if (is_loader_launch_efi(lctx)){ */ /* we were launched EFI, set efi_rsdt_ptr */ rsdp = (struct acpi_rsdp*)efi_get_rsdp(); if (rsdp != NULL){ if (version < 6){ /* rsdt */ /* NOTE: Winston Wang says this doesn't work for v5 */ os_sinit_data->efi_rsdt_ptr = (uint64_t) rsdp->rsdp1.rsdt; } else { /* rsdp */ memcpy((void *)&g_rsdp, rsdp, sizeof(struct acpi_rsdp)); os_sinit_data->efi_rsdt_ptr = (uint64_t)&g_rsdp; } } else { /* per discussions--if we don't have an ACPI pointer, die */ printk(TBOOT_ERR"Failed to find RSDP for EFI launch\n"); return NULL; } /* capabilities : choose DA/LG */ os_sinit_data->capabilities.pcr_map_no_legacy = 1; if ( sinit_caps.pcr_map_da && get_tboot_prefer_da() ) os_sinit_data->capabilities.pcr_map_da = 1; else if ( !sinit_caps.pcr_map_no_legacy ) os_sinit_data->capabilities.pcr_map_no_legacy = 0; else if ( sinit_caps.pcr_map_da ) { printk(TBOOT_INFO "DA is the only supported PCR mapping by SINIT, use it\n"); os_sinit_data->capabilities.pcr_map_da = 1; } else { printk(TBOOT_ERR"SINIT capabilities are incompatible (0x%x)\n", sinit_caps._raw); return NULL; } g_using_da = os_sinit_data->capabilities.pcr_map_da; /* PCR mapping selection MUST be zero in TPM2.0 mode * since D/A mapping is the only supported by TPM2.0 */ if ( g_tpm->major >= TPM20_VER_MAJOR ) { os_sinit_data->flags = (g_tpm->extpol == TB_EXTPOL_AGILE) ? 0 : 1; os_sinit_data->capabilities.pcr_map_no_legacy = 0; os_sinit_data->capabilities.pcr_map_da = 0; g_using_da = 1; } /* Event log initialization */ if ( os_sinit_data->version >= 6 ) init_os_sinit_ext_data(os_sinit_data->ext_data_elts); print_os_sinit_data(os_sinit_data); /* * SINIT to MLE data will be setup by SINIT */ return txt_heap; } bool txt_is_launched(void) { txt_sts_t sts; sts._raw = read_pub_config_reg(TXTCR_STS); return sts.senter_done_sts; } tb_error_t txt_launch_environment(void) { os_mle_data_t *os_mle_data; txt_heap_t *txt_heap; /* print some debug info */ print_file_info(); /* MLE page table already setup earlier */ /* initialize TXT heap */ txt_heap = init_txt_heap(g_mle_pt, g_sinit); if ( txt_heap == NULL ) return TB_ERR_TXT_NOT_SUPPORTED; /* save MTRRs before we alter them for SINIT launch */ os_mle_data = get_os_mle_data_start(txt_heap); save_mtrrs(&(os_mle_data->saved_mtrr_state)); /* set MTRRs properly for AC module (SINIT) */ if ( !set_mtrrs_for_acmod(g_sinit) ) return TB_ERR_FATAL; /* deactivate current locality */ if (g_tpm_family == TPM_IF_20_CRB ) { printk(TBOOT_INFO"Relinquish CRB localility 0 before executing GETSEC[SENTER]...\n"); if (!tpm_relinquish_locality_crb(0)){ printk(TBOOT_INFO"Relinquish CRB locality 0 failed...\n"); apply_policy(TB_ERR_TPM_NOT_READY) ; } } /* Left behind commented out mess */ printk(TBOOT_INFO"executing GETSEC[SENTER]...\n"); /* (optionally) pause before executing GETSEC[SENTER] */ if ( g_vga_delay > 0 ) delay(g_vga_delay * 1000); /* SINIT has be (and is) located below 4G for SENTER */ __getsec_senter((uint32_t)(uint64_t)g_sinit, (g_sinit->size)*4); printk(TBOOT_INFO"ERROR--we should not get here!\n"); return TB_ERR_FATAL; } bool txt_prepare_cpu(void) { unsigned long cr0; uint64_t mcg_cap, mcg_stat, msr_efer, rflags; /* must be running at CPL 0 => this is implicit in even getting this far */ /* since our bootstrap code loads a GDT, etc. */ msr_efer = rdmsr(MSR_EFER); /* must be in IA-32e 16b sub-mode */ if ( !( msr_efer & (1 << _EFER_LMA) ) ) { printk(TBOOT_ERR"ERR: not in IA-32e 16bit sub- mode\n"); return false; } cr0 = read_cr0(); /* cache must be enabled (CR0.CD = CR0.NW = 0) */ if ( cr0 & CR0_CD ) { printk(TBOOT_INFO"CR0.CD set\n"); cr0 &= ~CR0_CD; } if ( cr0 & CR0_NW ) { printk(TBOOT_INFO"CR0.NW set\n"); cr0 &= ~CR0_NW; } /* native FPU error reporting must be enabled for proper */ /* interaction behavior */ if ( !(cr0 & CR0_NE) ) { printk(TBOOT_INFO"CR0.NE not set\n"); cr0 |= CR0_NE; } write_cr0(cr0); /* cannot be in virtual-8086 mode (EFLAGS.VM=1) */ rflags = read_rflags(); if ( rflags & X86_EFLAGS_VM ) { printk(TBOOT_INFO"EFLAGS.VM set\n"); write_rflags(rflags | ~X86_EFLAGS_VM); } printk(TBOOT_INFO"IA32_EFER, CR0 and EFLAGS OK\n"); /* * verify that we're not already in a protected environment */ if ( txt_is_launched() ) { printk(TBOOT_ERR"already in protected environment\n"); return false; } /* * verify all machine check status registers are clear (unless * support preserving them) */ /* no machine check in progress (IA32_MCG_STATUS.MCIP=1) */ mcg_stat = rdmsr(MSR_MCG_STATUS); if ( mcg_stat & 0x04 ) { printk(TBOOT_ERR"machine check in progress\n"); return false; } getsec_parameters_t params; if ( !get_parameters(¶ms) ) { printk(TBOOT_ERR"get_parameters() failed\n"); return false; } /* check if all machine check regs are clear */ mcg_cap = rdmsr(MSR_MCG_CAP); for ( unsigned int i = 0; i < (mcg_cap & 0xff); i++ ) { mcg_stat = rdmsr(MSR_MC0_STATUS + 4*i); if ( mcg_stat & (1ULL << 63) ) { printk(TBOOT_ERR"MCG[%u] = %Lx ERROR\n", i, mcg_stat); if ( !params.preserve_mce ) return false; } } if ( params.preserve_mce ) printk(TBOOT_INFO"supports preserving machine check errors\n"); else printk(TBOOT_INFO"no machine check errors\n"); if ( params.proc_based_scrtm ) printk(TBOOT_INFO"CPU support processor-based S-CRTM\n"); /* all is well with the processor state */ printk(TBOOT_INFO"CPU is ready for SENTER\n"); return true; } bool txt_is_powercycle_required(void) { /* a powercycle is required to clear the TXT_RESET.STS flag */ txt_ests_t ests = (txt_ests_t)read_pub_config_reg(TXTCR_ESTS); return ests.txt_reset_sts; } #define ACM_MEM_TYPE_UC 0x0100 #define ACM_MEM_TYPE_WC 0x0200 #define ACM_MEM_TYPE_WT 0x1000 #define ACM_MEM_TYPE_WP 0x2000 #define ACM_MEM_TYPE_WB 0x4000 #define DEF_ACM_MAX_SIZE 0x8000 #define DEF_ACM_VER_MASK 0xffffffff #define DEF_ACM_VER_SUPPORTED 0x00 #define DEF_ACM_MEM_TYPES ACM_MEM_TYPE_UC #define DEF_SENTER_CTRLS 0x00 bool get_parameters(getsec_parameters_t *params) { unsigned long long cr4; uint32_t index, eax, ebx, ecx; int param_type; /* sanity check because GETSEC[PARAMETERS] will fail if not set */ cr4 = read_cr4(); if ( !(cr4 & CR4_SMXE) ) { printk(TBOOT_ERR"SMXE not enabled, can't read parameters - cr4: %llx\n", cr4); return false; } memset(params, 0, sizeof(*params)); params->acm_max_size = DEF_ACM_MAX_SIZE; params->acm_mem_types = DEF_ACM_MEM_TYPES; params->senter_controls = DEF_SENTER_CTRLS; params->proc_based_scrtm = false; params->preserve_mce = false; index = 0; do { __getsec_parameters(index++, ¶m_type, &eax, &ebx, &ecx); /* the code generated for a 'switch' statement doesn't work in this */ /* environment, so use if/else blocks instead */ /* NULL - all reserved */ if ( param_type == 0 ) ; /* supported ACM versions */ else if ( param_type == 1 ) { if ( params->n_versions == MAX_SUPPORTED_ACM_VERSIONS ) printk(TBOOT_WARN"number of supported ACM version exceeds " "MAX_SUPPORTED_ACM_VERSIONS\n"); else { params->acm_versions[params->n_versions].mask = ebx; params->acm_versions[params->n_versions].version = ecx; params->n_versions++; } } /* max size AC execution area */ else if ( param_type == 2 ) params->acm_max_size = eax & 0xffffffe0; /* supported non-AC mem types */ else if ( param_type == 3 ) params->acm_mem_types = eax & 0xffffffe0; /* SENTER controls */ else if ( param_type == 4 ) params->senter_controls = (eax & 0x00007fff) >> 8; /* TXT extensions support */ else if ( param_type == 5 ) { params->proc_based_scrtm = (eax & 0x00000020) ? true : false; params->preserve_mce = (eax & 0x00000040) ? true : false; } else { printk(TBOOT_WARN"unknown GETSEC[PARAMETERS] type: %d\n", param_type); param_type = 0; /* set so that we break out of the loop */ } } while ( param_type != 0 ); if ( params->n_versions == 0 ) { params->acm_versions[0].mask = DEF_ACM_VER_MASK; params->acm_versions[0].version = DEF_ACM_VER_SUPPORTED; params->n_versions = 1; } return true; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */