/* @file * STM platform SMM API * * Copyright (c) 2015, Intel Corporation. All rights reserved. * This program and the accompanying materials are licensed and made * available under the terms and conditions of the BSD License which * accompanies this distribution. The full text of the license may be found * at http://opensource.org/licenses/bsd-license.php. * * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR * IMPLIED. * */ #include #include #include #include #include #include #include #include #include #include #include #include /* * Load STM image to MSEG * * @retval SUCCESS STM is loaded to MSEG */ int load_stm_image(uintptr_t mseg) { int status; void *mseg_base; uint32_t stm_buffer_size; uint32_t stm_image_size; bool stm_status; STM_HEADER *stm_header; // Extract STM image from FV mseg_base = (void *)mseg; stm_buffer_size = CONFIG_MSEG_SIZE; stm_image_size = 0; memset((void *)mseg_base, 0, CONFIG_MSEG_SIZE); // clear the mseg stm_image_size = cbfs_boot_load_file("stm.bin", mseg_base, stm_buffer_size, CBFS_TYPE_RAW); printk(BIOS_DEBUG, "STM:loaded into mseg: 0x%p size: %u\n", mseg_base, stm_image_size); /* status is number of bytes loaded */ stm_status = stm_check_stm_image(mseg_base, stm_image_size); if (!stm_status) { printk(BIOS_DEBUG, "STM: Error in STM image\n"); return -1; } stm_header = mseg_base; stm_gen_4g_pagetable_x64((uint32_t)mseg_base + stm_header->hw_stm_hdr.cr3_offset); // Debug stuff printk(BIOS_DEBUG, "STM: Header-Revision %d Features 0x%08x Cr3Offset 0x%08x\n", stm_header->hw_stm_hdr.stm_header_revision, stm_header->hw_stm_hdr.monitor_features, stm_header->hw_stm_hdr.cr3_offset); printk(BIOS_DEBUG, "STM: Header-StaticImageSize: %d Cr3Location: 0x%08x\n", stm_header->sw_stm_hdr.static_image_size, ((uint32_t)mseg_base + stm_header->hw_stm_hdr.cr3_offset)); status = 0; // always return good for now return status; } struct descriptor { uint16_t limit; uintptr_t base; } __attribute__((packed)); static void read_gdtr(struct descriptor *gdtr) { __asm__ __volatile__("sgdt %0" : "=m"(*gdtr)); } void setup_smm_descriptor(void *smbase, void *base_smbase, int32_t apic_id, int32_t entry32_off) { struct descriptor gdtr; void *smbase_processor; //msr_t smbase_msr; TXT_PROCESSOR_SMM_DESCRIPTOR *psd; smbase_processor = (void *) SMM_DEFAULT_BASE;//we are here psd = smbase + SMM_PSD_OFFSET; printk(BIOS_DEBUG, "STM: Smm Descriptor setup: Smbase: %p Smbase_processor: %p Psd: %p\n", smbase, smbase_processor, psd); memset(psd, 0, sizeof(TXT_PROCESSOR_SMM_DESCRIPTOR)); memcpy(&psd->signature, TXT_PROCESSOR_SMM_DESCRIPTOR_SIGNATURE, 8); psd->smm_descriptor_ver_major = TXT_PROCESSOR_SMM_DESCRIPTOR_VERSION_MAJOR; psd->smm_descriptor_ver_minor = TXT_PROCESSOR_SMM_DESCRIPTOR_VERSION_MINOR; psd->smm_smi_handler_rip = (uint64_t)((uintptr_t)base_smbase + SMM_ENTRY_OFFSET + entry32_off); psd->local_apic_id = apic_id; psd->size = sizeof(TXT_PROCESSOR_SMM_DESCRIPTOR); psd->acpi_rsdp = 0; psd->bios_hw_resource_requirements_ptr = (uint64_t)((uintptr_t)get_stm_resource()); psd->smm_cs = ROM_CODE_SEG; psd->smm_ds = ROM_DATA_SEG; psd->smm_ss = ROM_DATA_SEG; psd->smm_other_segment = ROM_DATA_SEG; psd->smm_tr = SMM_TASK_STATE_SEG; // At this point the coreboot smm_stub is relative to the default // smbase and not the one for the smi handler in tseg. So we have // to adjust the gdtr.base read_gdtr(&gdtr); gdtr.base -= (uintptr_t) smbase_processor; gdtr.base += (uintptr_t) base_smbase; psd->smm_gdt_ptr = gdtr.base; psd->smm_gdt_size = gdtr.limit + 1; // the stm will subtract, so add printk(BIOS_DEBUG, "STM: Smm Descriptor setup complete - Smbase: %p Psd: %p\n", smbase, psd); } extern uint8_t *stm_resource_heap; #define FXSAVE_SIZE 512 static int stm_load_status = 0; void stm_setup(uintptr_t mseg, int cpu, int num_cpus, uintptr_t smbase, uintptr_t base_smbase, uint32_t offset32) { msr_t InitMseg; msr_t MsegChk; msr_t vmx_basic; uintptr_t addr_calc; // used to calculate the stm resource heap area printk(BIOS_DEBUG, "STM: set up for cpu %d/%d\n", cpu, num_cpus); vmx_basic = rdmsr(IA32_VMX_BASIC_MSR); // Does this processor support an STM? if ((vmx_basic.hi & VMX_BASIC_HI_DUAL_MONITOR) != VMX_BASIC_HI_DUAL_MONITOR) { printk(BIOS_WARNING, "STM: not supported on CPU %d\n", cpu); return; } if (cpu == 0) { // need to create the BIOS resource list once // first calculate the location in SMRAM addr_calc = mseg - CONFIG_BIOS_RESOURCE_LIST_SIZE; stm_resource_heap = (uint8_t *) addr_calc; printk(BIOS_DEBUG, "STM: stm_resource_heap located at %p\n", stm_resource_heap); //setup the the list 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); } }