# HG changeset patch # User root@jcihula-lt32.bj.intel.com # Node ID 843be4e340c8f15f7fe0c44ce39f0e87a9f14cf6 # Parent 765b7e23d979cce7e27059b71f48be0aaedb6395 Adds Intel(R) LaGrande Technology (LT) Safer Mode Extensions (SMX) support Signed-off-by: Joseph Cihula Signed-off-by: Burzin Daruwala diff -r 765b7e23d979 -r 843be4e340c8 Config.mk --- a/Config.mk Fri Sep 01 01:25:15 2006 +0100 +++ b/Config.mk Fri Sep 01 18:28:21 2006 +0800 @@ -7,6 +7,13 @@ XEN_COMPILE_ARCH ?= $(shell uname -m -e s/ppc/powerpc/) XEN_TARGET_ARCH ?= $(XEN_COMPILE_ARCH) XEN_TARGET_X86_PAE ?= n + +# LaGrande Technology (LT) Safer Mode Extensions (SMX) +INTEL_SMX ?= n +# TBD: fix for x86_64 +ifeq ($(x86_64),y) +INTEL_SMX := n +endif # Tools to run on system hosting the build HOSTCC = gcc diff -r 765b7e23d979 -r 843be4e340c8 xen/Rules.mk --- a/xen/Rules.mk Fri Sep 01 01:25:15 2006 +0100 +++ b/xen/Rules.mk Fri Sep 01 18:28:21 2006 +0800 @@ -57,6 +57,7 @@ CFLAGS-$(crash_debug) += -DCRASH_DEBUG CFLAGS-$(crash_debug) += -DCRASH_DEBUG CFLAGS-$(perfc) += -DPERF_COUNTERS CFLAGS-$(perfc_arrays) += -DPERF_ARRAYS +CFLAGS-$(INTEL_SMX) += -DCONFIG_SMX ifneq ($(max_phys_cpus),) CFLAGS-y += -DMAX_PHYS_CPUS=$(max_phys_cpus) diff -r 765b7e23d979 -r 843be4e340c8 xen/arch/x86/Makefile --- a/xen/arch/x86/Makefile Fri Sep 01 01:25:15 2006 +0100 +++ b/xen/arch/x86/Makefile Fri Sep 01 18:28:21 2006 +0800 @@ -2,6 +2,7 @@ subdir-y += cpu subdir-y += cpu subdir-y += genapic subdir-y += hvm +subdir-$(INTEL_SMX) += smx subdir-y += mm subdir-y += oprofile diff -r 765b7e23d979 -r 843be4e340c8 xen/arch/x86/boot/x86_32.S --- a/xen/arch/x86/boot/x86_32.S Fri Sep 01 01:25:15 2006 +0100 +++ b/xen/arch/x86/boot/x86_32.S Fri Sep 01 18:28:21 2006 +0800 @@ -9,6 +9,10 @@ .text +#ifdef CONFIG_SMX + .global __start +#endif + ENTRY(start) ENTRY(stext) ENTRY(_stext) @@ -71,7 +75,17 @@ 1: lss stack_start-__PAGE_OFFSE cmp $(SECONDARY_CPU_FLAG),%ebx je start_paging - + +#ifdef CONFIG_SMX + /* if this is a re-start due to SENTER then eax was cleared, so */ + /* set it back */ + mov $_senter_start-__PAGE_OFFSET,%ecx + cmp $0x01,(%ecx) + jne skip_set + mov $0x2BADB002,%eax + +skip_set: +#endif /* Check for Multiboot bootloader */ cmp $0x2BADB002,%eax jne not_multiboot @@ -86,6 +100,16 @@ 1: lss stack_start-__PAGE_OFFSE /* Save the Multiboot info structure for later use. */ add $__PAGE_OFFSET,%ebx push %ebx + +#ifdef CONFIG_SMX + /* call measured launch code */ + call start_smx + + /* after SENTER, ebx is cleared, so start_smx returns saved value */ + /* which we move back to ebx */ + mov %eax,%ebx + push %ebx +#endif #ifdef CONFIG_X86_PAE /* Initialize low and high mappings of all memory with 2MB pages */ diff -r 765b7e23d979 -r 843be4e340c8 xen/arch/x86/domain_build.c --- a/xen/arch/x86/domain_build.c Fri Sep 01 01:25:15 2006 +0100 +++ b/xen/arch/x86/domain_build.c Fri Sep 01 18:28:21 2006 +0800 @@ -26,6 +26,10 @@ #include #include #include +#ifdef CONFIG_SMX +#include +#include +#endif #include #include @@ -851,6 +855,25 @@ int construct_dom0(struct domain *d, rc |= iomem_deny_access(dom0, mfn, mfn); } +#ifdef CONFIG_SMX + if ( smx_in_prot_env() ) { + /* + * remove permissions for LT private config register space and + * all of LT device memory except TPM localities 0,1 + */ + + /* private config regs */ + mfn = paddr_to_pfn(LT_PRIV_CONFIG_REGS_BASE); + rc |= iomem_deny_access(dom0, mfn, mfn + NR_LT_CONFIG_PAGES - 1); + + /* + * TBD: access to non-available device memory needs to return 0xff + * so we will need to map a page of 0xff's to all ranges except for + * TPM localities 0,1 + */ + } +#endif + BUG_ON(rc != 0); return 0; diff -r 765b7e23d979 -r 843be4e340c8 xen/arch/x86/e820.c --- a/xen/arch/x86/e820.c Fri Sep 01 01:25:15 2006 +0100 +++ b/xen/arch/x86/e820.c Fri Sep 01 18:28:21 2006 +0800 @@ -31,7 +31,7 @@ static void __init add_memory_region(uns } } /* add_memory_region */ -static void __init print_e820_memory_map(struct e820entry *map, int entries) +void __init print_e820_memory_map(struct e820entry *map, int entries) { int i; @@ -51,6 +51,11 @@ static void __init print_e820_memory_map case E820_NVS: printk("(ACPI NVS)\n"); break; +#ifdef CONFIG_SMX + case E820_PROTECTED: + printk("(PROTECTED)\n"); + break; +#endif default: printk("type %u\n", map[i].type); break; } diff -r 765b7e23d979 -r 843be4e340c8 xen/arch/x86/hvm/vmx/vmx.c --- a/xen/arch/x86/hvm/vmx/vmx.c Fri Sep 01 01:25:15 2006 +0100 +++ b/xen/arch/x86/hvm/vmx/vmx.c Fri Sep 01 18:28:21 2006 +0800 @@ -777,7 +777,8 @@ int start_vmx(void) if ( eax & IA32_FEATURE_CONTROL_MSR_LOCK ) { - if ( (eax & IA32_FEATURE_CONTROL_MSR_ENABLE_VMXON) == 0x0 ) + if ( (eax & (IA32_FEATURE_CONTROL_MSR_ENABLE_VMX_OUT_SMX | + IA32_FEATURE_CONTROL_MSR_ENABLE_VMX_IN_SMX) ) == 0x0) { printk("VMX disabled by Feature Control MSR.\n"); return 0; @@ -787,7 +788,7 @@ int start_vmx(void) { wrmsr(IA32_FEATURE_CONTROL_MSR, IA32_FEATURE_CONTROL_MSR_LOCK | - IA32_FEATURE_CONTROL_MSR_ENABLE_VMXON, 0); + IA32_FEATURE_CONTROL_MSR_ENABLE_VMX_OUT_SMX, 0); } if ( !check_vmx_controls(MONITOR_PIN_BASED_EXEC_CONTROLS, diff -r 765b7e23d979 -r 843be4e340c8 xen/arch/x86/mm.c --- a/xen/arch/x86/mm.c Fri Sep 01 01:25:15 2006 +0100 +++ b/xen/arch/x86/mm.c Fri Sep 01 18:28:21 2006 +0800 @@ -215,7 +215,12 @@ void arch_init_memory(void) /* Any areas not specified as RAM by the e820 map are considered I/O. */ for ( i = 0, pfn = 0; i < e820.nr_map; i++ ) { +#ifdef CONFIG_SMX + if ( e820.map[i].type != E820_RAM && + e820.map[i].type != E820_PROTECTED ) +#else if ( e820.map[i].type != E820_RAM ) +#endif continue; /* Every page from cursor to start of next RAM region is I/O. */ rstart_pfn = PFN_UP(e820.map[i].addr); diff -r 765b7e23d979 -r 843be4e340c8 xen/arch/x86/setup.c --- a/xen/arch/x86/setup.c Fri Sep 01 01:25:15 2006 +0100 +++ b/xen/arch/x86/setup.c Fri Sep 01 18:28:21 2006 +0800 @@ -25,6 +25,9 @@ #include #include #include +#ifdef CONFIG_SMX +#include +#endif #include extern void dmi_scan_machine(void); @@ -328,6 +331,25 @@ void __init __start_xen(multiboot_info_t "(truncated length fields).\n"); max_page = init_e820(e820_raw, &e820_raw_nr); + +#ifdef CONFIG_SMX + if ( smx_in_prot_env() ) { + /* + * set the LT memory regions to be reserved/protected regardless of + * what BIOS may have set them to, since we don't trust BIOS + */ + + /* we can't let execution continue if the LT memory regions */ + /* haven't been protected */ + /* TBD: we could just teardown the protected environment */ + if ( smx_reserve_memory(&e820) == -1 ) { + printk("SMX: e820 map too small to protect LT memory regions\n"); + EARLY_FAIL(); + } + printk(KERN_INFO "Physical RAM map after LT regions added:\n"); + print_e820_memory_map(e820.map, e820.nr_map); + } +#endif modules_length = mod[mbi->mods_count-1].mod_end - mod[0].mod_start; @@ -559,6 +581,20 @@ void __init __start_xen(multiboot_info_t if ( opt_watchdog ) watchdog_enable(); +#ifdef CONFIG_SMX + if ( smx_in_prot_env() ) { + /* + * initialize the fixmap entries for LT pub/priv config regs + */ + for ( i = 0; i < NR_LT_CONFIG_PAGES; i++ ) { + set_fixmap_nocache(FIX_LT_PUB_CONFIG_REGS_BASE + i, + LT_PUB_CONFIG_REGS_BASE + i*PAGE_SIZE); + set_fixmap_nocache(FIX_LT_PRIV_CONFIG_REGS_BASE + i, + LT_PRIV_CONFIG_REGS_BASE + i*PAGE_SIZE); + } + } +#endif + /* initialize access control security module */ acm_init(&initrdidx, mbi, initial_images_start); diff -r 765b7e23d979 -r 843be4e340c8 xen/arch/x86/shutdown.c --- a/xen/arch/x86/shutdown.c Fri Sep 01 01:25:15 2006 +0100 +++ b/xen/arch/x86/shutdown.c Fri Sep 01 18:28:21 2006 +0800 @@ -21,6 +21,9 @@ #include #include #include +#ifdef CONFIG_SMX +#include +#endif /* reboot_str: comma-separated list of reboot options. */ static char __initdata reboot_str[10] = ""; @@ -49,6 +52,20 @@ void machine_halt(void) watchdog_disable(); console_start_sync(); smp_call_function(__machine_halt, NULL, 1, 0); + +#ifdef CONFIG_SMX + /* clear any sensitive info in BSP (if in protected env) */ + smx_scrub_proc(); + + /* clear any sensitive info in memory (if in protected env) */ + smx_scrub_mem(); + + hvm_disable(); + + /* teardown the protected environment (if any) */ + smx_teardown(); +#endif + __machine_halt(NULL); } @@ -212,6 +229,10 @@ void machine_restart(char * __unused) /* Send IPI to the boot CPU (logical cpu 0). */ on_selected_cpus(cpumask_of_cpu(0), (void *)machine_restart, NULL, 1, 0); +#ifdef CONFIG_SMX + /* clear any sensitive info in processor (if in protected env) */ + smx_scrub_proc(); +#endif for ( ; ; ) safe_halt(); } @@ -222,7 +243,26 @@ void machine_restart(char * __unused) */ smp_send_stop(); disable_IO_APIC(); + +#ifdef CONFIG_SMX + /* clear any sensitive info in BSP (if in protected env) */ + smx_scrub_proc(); + + /* clear any sensitive info in memory (if in protected env) */ + smx_scrub_mem(); +#endif + hvm_disable(); + +#ifdef CONFIG_SMX + /* teardown the protected environment (if any) */ + smx_teardown(); + + /* TBD: eventually cap PCRs and allow restart without reboot, but until */ + /* then prevent restart without platform reboot that clears PCRs */ + /* regardless of whether we actually launched the protected environment */ + reboot_thru_bios = 0; +#endif /* Rebooting needs to touch the page at absolute address 0. */ *((unsigned short *)__va(0x472)) = reboot_mode; diff -r 765b7e23d979 -r 843be4e340c8 xen/common/domctl.c --- a/xen/common/domctl.c Fri Sep 01 01:25:15 2006 +0100 +++ b/xen/common/domctl.c Fri Sep 01 18:28:21 2006 +0800 @@ -19,6 +19,10 @@ #include #include #include +#ifdef CONFIG_SMX +#include +#include +#endif #include #include @@ -619,12 +623,45 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domc case XEN_DOMCTL_iomem_permission: { struct domain *d; +#ifdef CONFIG_SMX + unsigned long prot_mfn_s; + unsigned long prot_mfn_e; +#endif unsigned long mfn = op->u.iomem_permission.first_mfn; unsigned long nr_mfns = op->u.iomem_permission.nr_mfns; ret = -EINVAL; if ( (mfn + nr_mfns - 1) < mfn ) /* wrap? */ break; + +#ifdef CONFIG_SMX + if ( smx_in_prot_env() ) { + /* + * we need to prohibit mapping LT private config registers and + * all of LT device memory except TPM localities 0,1 + */ + + /* private config regs */ + prot_mfn_s = paddr_to_pfn(LT_PRIV_CONFIG_REGS_BASE); + prot_mfn_e = prot_mfn_s + NR_LT_CONFIG_PAGES; + if ( mfn >= prot_mfn_s && mfn < prot_mfn_e ) { + printk("SMX: DOM0_IOMEM_PERMISSION attempt to access LT " + "region (mfn=%lx, nr_mfns=%lx)\n", mfn, nr_mfns); + break; + } + if ( mfn < prot_mfn_s && (mfn + nr_mfns) > prot_mfn_s ) { + printk("SMX: DOM0_IOMEM_PERMISSION attempt to access LT " + "region (mfn=%lx, nr_mfns=%lx)\n", mfn, nr_mfns); + break; + } + + /* + * TBD: access to non-available device memory needs to return 0xff + * so we will need to map a page of 0xff's to all ranges except for + * TPM localities 0,1 + */ + } +#endif ret = -ESRCH; d = find_domain_by_id(op->domain); diff -r 765b7e23d979 -r 843be4e340c8 xen/include/asm-x86/cpufeature.h --- a/xen/include/asm-x86/cpufeature.h Fri Sep 01 01:25:15 2006 +0100 +++ b/xen/include/asm-x86/cpufeature.h Fri Sep 01 18:28:21 2006 +0800 @@ -76,6 +76,7 @@ #define X86_FEATURE_MWAIT (4*32+ 3) /* Monitor/Mwait support */ #define X86_FEATURE_DSCPL (4*32+ 4) /* CPL Qualified Debug Store */ #define X86_FEATURE_VMXE (4*32+ 5) /* Virtual Machine Extensions */ +#define X86_FEATURE_SMXE (4*32+ 6) /* Safer Mode Extensions */ #define X86_FEATURE_EST (4*32+ 7) /* Enhanced SpeedStep */ #define X86_FEATURE_TM2 (4*32+ 8) /* Thermal Monitor 2 */ #define X86_FEATURE_CID (4*32+10) /* Context ID */ diff -r 765b7e23d979 -r 843be4e340c8 xen/include/asm-x86/e820.h --- a/xen/include/asm-x86/e820.h Fri Sep 01 01:25:15 2006 +0100 +++ b/xen/include/asm-x86/e820.h Fri Sep 01 18:28:21 2006 +0800 @@ -11,6 +11,7 @@ struct e820map { }; extern unsigned long init_e820(struct e820entry *, int *); +extern void print_e820_memory_map(struct e820entry *, int); extern struct e820map e820; #endif /*__E820_HEADER*/ diff -r 765b7e23d979 -r 843be4e340c8 xen/include/asm-x86/fixmap.h --- a/xen/include/asm-x86/fixmap.h Fri Sep 01 01:25:15 2006 +0100 +++ b/xen/include/asm-x86/fixmap.h Fri Sep 01 18:28:21 2006 +0800 @@ -16,6 +16,10 @@ #include #include #include +#ifdef CONFIG_SMX +#include +#include +#endif /* * Here we define all the compile-time 'special' virtual @@ -36,6 +40,11 @@ enum fixed_addresses { FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1, FIX_HPET_BASE, FIX_CYCLONE_TIMER, +#ifdef CONFIG_SMX + FIX_LT_PRIV_CONFIG_REGS_BASE, + FIX_LT_PUB_CONFIG_REGS_BASE = FIX_LT_PRIV_CONFIG_REGS_BASE + NR_LT_CONFIG_PAGES, + FIX_LT_CONFIG_REGS_END = FIX_LT_PUB_CONFIG_REGS_BASE + NR_LT_CONFIG_PAGES, +#endif __end_of_fixed_addresses }; diff -r 765b7e23d979 -r 843be4e340c8 xen/include/asm-x86/msr.h --- a/xen/include/asm-x86/msr.h Fri Sep 01 01:25:15 2006 +0100 +++ b/xen/include/asm-x86/msr.h Fri Sep 01 18:28:21 2006 +0800 @@ -116,9 +116,13 @@ static inline void wrmsrl(unsigned int m #define MSR_IA32_VMX_CR0_FIXED1 0x487 #define MSR_IA32_VMX_CR4_FIXED0 0x488 #define MSR_IA32_VMX_CR4_FIXED1 0x489 -#define IA32_FEATURE_CONTROL_MSR 0x3a -#define IA32_FEATURE_CONTROL_MSR_LOCK 0x1 -#define IA32_FEATURE_CONTROL_MSR_ENABLE_VMXON 0x4 + +#define IA32_FEATURE_CONTROL_MSR 0x3a +#define IA32_FEATURE_CONTROL_MSR_LOCK 0x1 +#define IA32_FEATURE_CONTROL_MSR_ENABLE_VMX_IN_SMX 0x2 +#define IA32_FEATURE_CONTROL_MSR_ENABLE_VMX_OUT_SMX 0x4 +#define IA32_FEATURE_CONTROL_MSR_SENTER_PARAM_CTL 0x7f00 +#define IA32_FEATURE_CONTROL_MSR_ENABLE_SENTER 0x8000 /* AMD/K8 specific MSRs */ #define MSR_EFER 0xc0000080 /* extended feature register */ @@ -145,8 +149,10 @@ static inline void wrmsrl(unsigned int m /* Intel MSRs. Some also available on other CPUs */ #define MSR_IA32_PLATFORM_ID 0x17 -#define MSR_MTRRcap 0x0fe -#define MSR_IA32_BBL_CR_CTL 0x119 +#define MSR_MTRRcap 0x0fe +#define MSR_IA32_MTRRCAP MSR_MTRRcap +#define MSR_IA32_MTRR_DEF_TYPE 0x2ff +#define MSR_IA32_BBL_CR_CTL 0x119 #define MSR_IA32_SYSENTER_CS 0x174 #define MSR_IA32_SYSENTER_ESP 0x175 diff -r 765b7e23d979 -r 843be4e340c8 xen/include/asm-x86/processor.h --- a/xen/include/asm-x86/processor.h Fri Sep 01 01:25:15 2006 +0100 +++ b/xen/include/asm-x86/processor.h Fri Sep 01 18:28:21 2006 +0800 @@ -80,6 +80,7 @@ #define X86_CR4_OSFXSR 0x0200 /* enable fast FPU save and restore */ #define X86_CR4_OSXMMEXCPT 0x0400 /* enable unmasked SSE exceptions */ #define X86_CR4_VMXE 0x2000 /* enable VMX */ +#define X86_CR4_SMXE 0x4000 /* enable SMX */ /* * Trap/fault mnemonics. diff -r 765b7e23d979 -r 843be4e340c8 xen/include/public/hvm/e820.h --- a/xen/include/public/hvm/e820.h Fri Sep 01 01:25:15 2006 +0100 +++ b/xen/include/public/hvm/e820.h Fri Sep 01 18:28:21 2006 +0800 @@ -12,6 +12,11 @@ #define E820_SHARED_PAGE 17 #define E820_XENSTORE 18 #define E820_BUFFERED_IO 19 + +#ifdef CONFIG_SMX +/* SMX extended E820 type */ +#define E820_PROTECTED 30 /* memory only available to hypervisor */ +#endif /* E820 location in HVM virtual address space. */ #define E820_MAP_PAGE 0x00090000 diff -r 765b7e23d979 -r 843be4e340c8 xen/arch/x86/smx/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/x86/smx/Makefile Fri Sep 01 18:28:21 2006 +0800 @@ -0,0 +1,6 @@ +obj-y += smx.o +obj-y += mtrrs.o +obj-y += acmod.o +obj-y += tpm.o +obj-y += errors.o +obj-y += early_printk.o diff -r 765b7e23d979 -r 843be4e340c8 xen/arch/x86/smx/acmod.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/x86/smx/acmod.c Fri Sep 01 18:28:21 2006 +0800 @@ -0,0 +1,321 @@ +/* + * acmod.c: support functions for use of LT Authenticated Code (AC) Modules + * + * Copyright (c) 2003-2006, 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 + +#define DEBUG_SMX 1 + +#undef printk +#ifdef DEBUG_SMX +#define printk early_serial_printk +#else +#define printk(_f , _a...) +#endif + +#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 + +/* this is arbitrary and can be increased when needed */ +#define MAX_SUPPORTED_ACM_VERSIONS 16 + +typedef struct { + struct { + u32 mask; + u32 version; + } acm_versions[MAX_SUPPORTED_ACM_VERSIONS]; + int n_versions; + u32 acm_max_size; + u32 acm_mem_types; + u32 senter_controls; +} getsec_parameters_t; + +#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 + +static int get_parameters(getsec_parameters_t *params) +{ + unsigned long cr4; + u32 index, eax, ebx, ecx; + int param_type; + + /* sanity check because GETSEC[PARAMETERS] will fail if not set */ + cr4 = read_cr4(); + if ( !(cr4 & X86_CR4_SMXE) ) { + printk("SMX: SMXE not enabled, can't read parameters\n"); + return -1; + } + + 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; + 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 */ + if ( param_type == 0 ) + ; + else if ( param_type == 1 ) { + if ( params->n_versions == MAX_SUPPORTED_ACM_VERSIONS ) + printk("SMX: 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++; + } + } + else if ( param_type == 2 ) + params->acm_max_size = eax & 0xffffffe0; + else if ( param_type == 3 ) + params->acm_mem_types = eax & 0xffffffe0; + else if ( param_type == 4 ) + params->senter_controls = (eax & 0x00007fff) >> 8; + else { + printk("SMX: 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 0; +} + +void dump_acm_hdr(acm_hdr_t *hdr, const char *mod_name) +{ + printk("SMX: AC module header dump for %s:\n", + (mod_name == NULL) ? "?" : mod_name); + printk("SMX: \ttype %x\n", hdr->module_type); + printk("SMX: \tlength %x\n", hdr->header_len); + printk("SMX: \tversion %x\n", hdr->header_ver); + printk("SMX: \tid %x\n", hdr->module_id); + printk("SMX: \tvendor %x\n", hdr->module_vendor); + printk("SMX: \tdate %08x\n", hdr->date); + printk("SMX: \tsize %x\n", hdr->size); + printk("SMX: \tentry point %08x:%08x\n", hdr->seg_sel, hdr->entry_point); +} + +int is_acmod(void *acmod_base) +{ + acm_hdr_t *acm_hdr; + + acm_hdr = (acm_hdr_t *)acmod_base; + + /* just check module_type */ + if ( acm_hdr->module_type != ACM_VALID_MOD_TYPE ) { + dump_acm_hdr(acm_hdr, (const char *)__pa("INVALID MODULE")); + return 0; + } + else + return 1; +} + +/* + * Do some AC module sanity checks because any violations will cause + * an LT.RESET. Instead detect these, print a desriptive message, + * and skip SENTER/ENTERACCS + */ +int verify_acmod(void *acmod_base) +{ + acm_hdr_t *acm_hdr; + getsec_parameters_t params; + u32 size; + + if ( !is_acmod(acmod_base) ) { + printk("SMX: not a valid AC module\n"); + return -1; + } + + acm_hdr = (acm_hdr_t *)acmod_base; + size = acm_hdr->size * 4; /* hdr size is in dwords, we want bytes */ + + /* + * AC mod must start on 4k page boundary + */ + + if ( (unsigned long)acmod_base & 0xfff ) { + printk("SMX: AC mod base not 4K aligned (%p)\n", acmod_base); + return -1; + } + printk("SMX: 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("SMX: AC mod size %x bogus\n", size); + return -1; + } + + if ( get_parameters(¶ms) == -1 ) { + printk("SMX: get_parameters() failed\n"); + return -1; + } + + if ( size > params.acm_max_size ) { + printk("SMX: AC mod size too large: %x (max=%x)\n", size, + params.acm_max_size); + return -1; + } + + printk("SMX: AC mod size OK\n"); + + /* + * perform checks on AC mod structure + */ + + /* print it for debugging */ + dump_acm_hdr(acm_hdr, (const char *)__pa("SINIT")); + + /* entry point is offset from base addr so make sure it is within module */ + if ( acm_hdr->entry_point >= size ) { + printk("SMX: AC mod entry (%08x) >= AC mod size (%08x)\n", + acm_hdr->entry_point, size); + return -1; + } + + 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("SMX: AC mod selector [%04x] bogus\n", acm_hdr->seg_sel); + return -1; + } + + /* TBD: verify that AC mod matches with chipset */ + + return 0; +} + +/* + * this must be done for each processor so that all have the same + * memory types + */ +int set_mtrrs_for_acmod(void *acmod_base, u32 acmod_size) +{ + unsigned long eflags; + unsigned long cr0, cr4; + + /* + * need to do some things before we start changing MTRRs + * + * since this will modify some of the MTRRs, they should be saved first + * so that they can be restored once the AC mod is done + */ + + /* disable interrupts */ + __save_flags(eflags); + __cli(); + + /* save CR0 then disable cache (CRO.CD=1, CR0.NW=0) */ + cr0 = read_cr0(); + write_cr0((cr0 & ~X86_CR0_NW) | X86_CR0_CD); + + /* flush caches */ + wbinvd(); + + /* save CR4 and disable global pages (CR4.PGE=0) */ + cr4 = read_cr4(); + write_cr4(cr4 & ~X86_CR4_PGE); + + /* flush TLBs */ + local_flush_tlb(); + + /* disable MTRRs */ + set_all_mtrrs(false); + + /* + * now set MTRRs for AC mod and rest of memory + */ + set_mem_type(acmod_base, acmod_size, MTRR_TYPE_WRBACK); + + /* + * now undo some of earlier changes and enable our new settings + */ + + /* flush caches */ + wbinvd(); + + /* flush TLBs */ + local_flush_tlb(); + + /* enable MTRRs */ + set_all_mtrrs(true); + + /* restore CR0 (cacheing) */ + write_cr0(cr0); + + /* restore CR4 (global pages) */ + write_cr4(cr4); + + /* enable interrupts */ + __restore_flags(eflags); + + return 0; +} + + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r 765b7e23d979 -r 843be4e340c8 xen/arch/x86/smx/early_printk.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/x86/smx/early_printk.c Fri Sep 01 18:28:21 2006 +0800 @@ -0,0 +1,254 @@ +/* + * early_printk.c: printk to serial for very early boot stages + * + * Copyright (c) 2006, Intel Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * + */ + +#include +#include +#include + +/* + * re-written parsing and formatting fns that don't rely on static data + */ + +static int isdigit( int c ) +{ + if ( c >= '0' && c <= '9' ) + return 1; + else + return 0; +} + +static char dec_digit( unsigned int i ) +{ + return ('0' + i); +} + +static char hex_digit( unsigned int i ) +{ + if ( i < 10 ) + return dec_digit( i ); + return ('a' + (i-10)); +} + +static void fmt_val( char *str, size_t size, unsigned long long arg, int is_dec ) +{ + char buf[128]; + char *str2 = str; + char *s; + + memset( buf, '\0', sizeof(buf) ); + + s = buf; + do { + if ( is_dec ) { + *s++ = dec_digit( (unsigned int)(arg % 10) ); + arg = arg / 10; + } + else { + *s++ = hex_digit( (unsigned int)(arg & 0x0f) ); + arg = arg >> 4; + } + } while ( arg != 0 ); + + /* buf is reversed string, so reverse copy */ + s--; + while ( s >= buf && size > 0 ) { + *str2++ = *s--; + size--; + } +} + +static void parse_fmt(char *str, size_t size, const char **pfmt, va_list *pap) +{ + const char *fmt = *pfmt; + int is_hex=0, is_dec=0, is_ptr=0, is_long=0, is_longlong=0, is_string=0; + int fill_size=0, fill_char=' '; + unsigned long long arg=0; + char buf[128]; + + fmt++; /* skip '%' */ + + /* width specifiers */ + if ( isdigit( *fmt ) ) { + if ( *fmt == '0' ) { + fill_char = '0'; + fmt++; + } + fill_size = simple_strtol(fmt, NULL, 10); + while ( isdigit( *fmt ) ) + fmt++; + } + + /* parse format specifier */ + if ( *fmt == 'L' ) { + is_longlong = 1; + fmt++; + } + else if ( *fmt == 'l' ) { + is_long = 1; + fmt++; + } + if ( *fmt == 'd' ) + is_dec = 1; + else if ( *fmt == 's' ) + is_string = 1; + else if ( *fmt == 'p' ) + is_ptr = 1; + else /* 'x' */ + is_hex = 1; + fmt++; + + /* get param converted to type */ + if ( is_longlong ) + arg = (unsigned long long)va_arg( *pap, unsigned long long ); + else if ( is_long ) + arg = (unsigned long long)va_arg( *pap, unsigned long ); + else if ( is_ptr ) + arg = (unsigned long long)(unsigned long)va_arg( *pap, void* ); + else if ( is_string ) + arg = (unsigned long long)(unsigned long)va_arg( *pap, char* ); + else + arg = (unsigned long long)va_arg( *pap, unsigned int ); + + /* handle neg # */ + if ( is_dec && (signed long long)arg < 0 ) { + *str++ = '-'; + size--; + arg = (unsigned long long)(-(signed long long)arg); + } + /* and %p */ + else if ( is_ptr && size > 2 ) { + *str++ = '0'; *str++ = 'x'; + size -= 2; + } + + memset( buf, '\0', sizeof(buf) ); + if ( is_string ) + strncpy( buf, (const char *)(unsigned long)arg, sizeof(buf)-1); + else + fmt_val( buf, sizeof(buf), arg, is_dec ); + + if ( fill_size < strlen( buf ) ) + fill_size = 0; + else + fill_size = fill_size - strlen( buf ); + + if ( strlen( buf ) + fill_size < size ) { + memset( str, fill_char, fill_size ); + strcpy( str + fill_size, buf ); + } + + /* move pfmt foreward */ + *pfmt = fmt; +} + +static int early_vscnprintf(char *str, size_t size, const char *fmt, + va_list ap) +{ + int n = 0; + + while ( *fmt != '\0' && n < size-1 ) { + if ( *fmt == '%' ) { + char buf[256]; + int sn; + + memset( buf, '\0', sizeof(buf) ); + + parse_fmt( buf, sizeof(buf), &fmt, &ap ); + + sn = strlen( buf ); + if ( sn > (size-n-1) ) + sn = size - n - 1; + strncpy( str, buf, sn ); + n += sn; str += sn; + } + else { + *str++ = *fmt++; + n++; + } + } + return n; +} + +/* + * serial support from linux.../arch/x86_64/kernel/early_printk.c + * + * this code does not initialize the serial port and assumes COM1, so + * it will only display if GRUB has been configured for output to COM1 + */ + +static int early_serial_base = 0x3f8; /* ttyS0 */ + +#define XMTRDY 0x20 + +#define DLAB 0x80 + +#define TXR 0 /* Transmit register (WRITE) */ +#define RXR 0 /* Receive register (READ) */ +#define IER 1 /* Interrupt Enable */ +#define IIR 2 /* Interrupt ID */ +#define FCR 2 /* FIFO control */ +#define LCR 3 /* Line control */ +#define MCR 4 /* Modem control */ +#define LSR 5 /* Line Status */ +#define MSR 6 /* Modem Status */ +#define DLL 0 /* Divisor Latch Low */ +#define DLH 1 /* Divisor latch High */ + +static int early_serial_putc(unsigned char ch) +{ + unsigned timeout = 0xffff; + while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout) + cpu_relax(); + outb(ch, early_serial_base + TXR); + return timeout ? 0 : -1; +} + +static void early_serial_write(const char *s, unsigned int n) +{ + while (*s && n-- > 0) { + early_serial_putc(*s); + if (*s == '\n') + early_serial_putc('\r'); + s++; + } +} + +void early_serial_printk(const char *fmt, ...) +{ + char buf[512]; + int n; + va_list ap; + + memset(buf, '\0', sizeof(buf)); + va_start(ap, fmt); + n = early_vscnprintf(buf, 512, (const char *)__pa(fmt), ap); + early_serial_write(buf, n); + va_end(ap); +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r 765b7e23d979 -r 843be4e340c8 xen/arch/x86/smx/errors.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/x86/smx/errors.c Fri Sep 01 18:28:21 2006 +0800 @@ -0,0 +1,108 @@ +/* + * errors.c: display LT error codes + * + * Copyright (c) 2003-2006, 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 + + +#define DEBUG_SMX 1 +#undef printk +#ifdef DEBUG_SMX +#define printk early_serial_printk +#else +#define printk(_f , _a...) /**/ +#endif + +/* + * format of LT.ERRORCODE's type field when its src field is 0 + */ +typedef union { + u16 _raw; + struct { + u16 type : 4; /* 0000=BIOS ACM, 0001=SINIT, 0010-1111=reserved */ + u16 progress : 6; + u16 error : 4; + u16 reserved : 1; + }; +} acmod_error_t; + +void display_errors(void) +{ + lt_crash_t err; + lt_ests_t ests; + lt_e2sts_t e2sts; + acmod_error_t acmod_err; + + /* + * display LT.CRASH error + */ + err = (lt_crash_t)read_pub_config_reg(LTCR_LT_CRASH); + printk("SMX: LT.CRASH=%Lx\n", err._raw); + + /* AC module error (don't know how to parse other errors) */ + if ( err.valid && err.src == 0 ) { + acmod_err = (acmod_error_t)(u16)(err.type); + printk("SMX: AC module error : type=%x, progress=%02x, error=%x\n", + (u32)acmod_err.type, (u32)acmod_err.progress, + (u32)acmod_err.error); + } + + /* + * display LT.ESTS error + */ + ests = (lt_ests_t)read_pub_config_reg(LTCR_LT_ESTS); + printk("SMX: LT.ESTS=%Lx\n", ests._raw); + + /* + * display LT.E2STS error + * - only valid if LT.WAKE-ERROR.STS set in LT.STS reg + */ + if ( ests.lt_wake_error_sts ) { + e2sts = (lt_e2sts_t)read_pub_config_reg(LTCR_LT_E2STS); + printk("SMX: LT.E2STS=%Lx\n", e2sts._raw); + } +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r 765b7e23d979 -r 843be4e340c8 xen/arch/x86/smx/mtrrs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/x86/smx/mtrrs.c Fri Sep 01 18:28:21 2006 +0800 @@ -0,0 +1,204 @@ +/* + * mtrrs.c: LT support functions for manipulating MTRRs + * + * Copyright (c) 2003-2006, 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 + +#define DEBUG_SMX 1 + +#undef printk +#ifdef DEBUG_SMX +#define printk early_serial_printk +#else +#define printk(_f , _a...) +#endif + +void save_mtrrs(mtrr_state_t *saved_state) +{ + mtrr_cap_t mtrr_cap; + int ndx; + + /* IA32_MTRR_DEF_TYPE MSR */ + rdmsrl(MSR_IA32_MTRR_DEF_TYPE, saved_state->mtrr_def_type.raw); + + /* number variable MTTRRs */ + rdmsrl(MSR_IA32_MTRRCAP, mtrr_cap.raw); + if ( mtrr_cap.vcnt > MAX_VARIABLE_MTRRS ) { + /* print warning but continue saving what we can */ + /* (set_mem_type() won't exceed the array, so we're safe doing this) */ + printk("SMX: actual # var MTRRs (%d) > MAX_VARIABLE_MTRRS (%d)\n", + mtrr_cap.vcnt, MAX_VARIABLE_MTRRS); + saved_state->num_var_mtrrs = MAX_VARIABLE_MTRRS; + } + else + saved_state->num_var_mtrrs = mtrr_cap.vcnt; + + /* physmask's and physbase's */ + for ( ndx = 0; ndx < saved_state->num_var_mtrrs; ndx++ ) { + rdmsrl(MTRR_PHYS_MASK0_MSR + ndx*2, + saved_state->mtrr_physmasks[ndx].raw); + rdmsrl(MTRR_PHYS_BASE0_MSR + ndx*2, + saved_state->mtrr_physbases[ndx].raw); + } +} + +void restore_mtrrs(mtrr_state_t *saved_state) +{ + int ndx; + + /* TBD: we need to check these for validity (e.g. overlaping regions */ + /* with invalid memory type combinations and variable MTRRs describing */ + /* non-contiguous memory regions) */ + + /* IA32_MTRR_DEF_TYPE MSR */ + wrmsrl(MSR_IA32_MTRR_DEF_TYPE, saved_state->mtrr_def_type.raw); + + /* physmask's and physbase's */ + for ( ndx = 0; ndx < saved_state->num_var_mtrrs; ndx++ ) { + wrmsrl(MTRR_PHYS_MASK0_MSR + ndx*2, + saved_state->mtrr_physmasks[ndx].raw); + wrmsrl(MTRR_PHYS_BASE0_MSR + ndx*2, + saved_state->mtrr_physbases[ndx].raw); + } +} + +/* + * set the memory type for specified range (base to base+size) + * to mem_type and everything else to UC + */ +int set_mem_type(void *base, u32 size, u32 mem_type) +{ + int num_pages; + int ndx; + mtrr_def_type_t mtrr_def_type; + mtrr_cap_t mtrr_cap; + mtrr_physmask_t mtrr_physmask; + mtrr_physbase_t mtrr_physbase; + + /* + * disable all fixed MTRRs + * set default type to UC + */ + rdmsrl(MSR_IA32_MTRR_DEF_TYPE, mtrr_def_type.raw); + mtrr_def_type.fe = 0; + mtrr_def_type.type = MTRR_TYPE_UNCACHABLE; + wrmsrl(MSR_IA32_MTRR_DEF_TYPE, mtrr_def_type.raw); + + /* + * initially disable all variable MTRRs (we'll enable the ones we use) + */ + rdmsrl(MSR_IA32_MTRRCAP, mtrr_cap.raw); + for ( ndx = 0; ndx < mtrr_cap.vcnt; ndx++ ) { + rdmsrl(MTRR_PHYS_MASK0_MSR + ndx*2, mtrr_physmask.raw); + mtrr_physmask.v = 0; + wrmsrl(MTRR_PHYS_MASK0_MSR + ndx*2, mtrr_physmask.raw); + } + + /* + * map all AC module pages as mem_type + */ + + num_pages = (size + PAGE_SIZE) >> PAGE_SHIFT; + ndx = 0; + + printk("SMX: setting MTRRs for acmod: base=%p, size=%x, num_pages=%d\n", + base, size, num_pages); + + while ( num_pages > 0 ) { + u32 pages_in_range; + + /* set the base of the current MTRR */ + rdmsrl(MTRR_PHYS_BASE0_MSR + ndx*2, mtrr_physbase.raw); + mtrr_physbase.base = (unsigned long)base >> PAGE_SHIFT; + mtrr_physbase.type = mem_type; + wrmsrl(MTRR_PHYS_BASE0_MSR + ndx*2, mtrr_physbase.raw); + + /* + * calculate MTRR mask + * MTRRs can map pages in power of 2 + * may need to use multiple MTRRS to map all of region + */ + pages_in_range = 1 << (fls(num_pages) - 1); + + rdmsrl(MTRR_PHYS_MASK0_MSR + ndx*2, mtrr_physmask.raw); + mtrr_physmask.mask = ~(pages_in_range - 1); + mtrr_physmask.v = 1; + wrmsrl(MTRR_PHYS_MASK0_MSR + ndx*2, mtrr_physmask.raw); + + /* prepare for the next loop depending on number of pages + * We figure out from the above how many pages could be used in this + * mtrr. Then we decrement the count, increment the base, + * increment the mtrr we are dealing with, and if num_pages is + * still not zero, we do it again. + */ + base += (pages_in_range * PAGE_SIZE); + num_pages -= pages_in_range; + ndx++; + if ( ndx == mtrr_cap.vcnt ) { + printk("SMX: exceeded number of var MTRRs when mapping range\n"); + return -1; + } + } + + return 0; +} + +/* enable/disable all MTRRs */ +void set_all_mtrrs(bool enable) +{ + mtrr_def_type_t mtrr_def_type; + + rdmsrl(MSR_IA32_MTRR_DEF_TYPE, mtrr_def_type.raw); + mtrr_def_type.e = enable ? 1 : 0; + wrmsrl(MSR_IA32_MTRR_DEF_TYPE, mtrr_def_type.raw); +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r 765b7e23d979 -r 843be4e340c8 xen/arch/x86/smx/smx.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/x86/smx/smx.c Fri Sep 01 18:28:21 2006 +0800 @@ -0,0 +1,966 @@ +/* + * smx.c: LT support functions and main entry points + * + * Copyright (c) 2003-2006, 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 + + +#define DEBUG_SMX 1 + +extern void * _text; /* start of text section */ +extern void * __start; /* Xen entry point in x86_{32,64}.S */ + + +/* + * flag to indicate when start_smx() is about to call SENTER + * used to determine if start_smx() is called first time or re-entry + * initialize to -1 so that it is not put in .bss (because .bss gets + * cleared each time before calling start_smx()) + * + * use this instead of reading LT.STS.SENTER_DONE_STS config reg + * to allow for possiblity that we were called already in a protected + * environment; we need to know if our code launched it or not + */ +int _senter_start = -1; + + +/* + * this is the structure whose addr we'll put in LT heap + */ +static mvmm_hdr_t _mvmm_hdr = { + /* fixed values for ver 1.0 */ + guid : {0x9082ac5a, 0x74a7476f, 0xa2555c0f, 0x42b651cb}, + length : sizeof(mvmm_hdr_t), + version : 0x00010000, + entry_point : 0x00000000, /* will be filled in later */ + req_mem_size : 0, /* Xen doesn't use this */ + features : 0x00000000 +}; + + +/* + * we need to save these values in order to use when modifying the e820 map + * to reserve the LT regions because this gets done after paging has been + * enabled but before the fixmap has been initialized with the LT config + * registers regions, so the current code for reading the registers directly + * won't work at that time + */ +static struct lt_memory_regions_t { + u64 heap_base, heap_size; + u64 sinit_base, sinit_size; + u64 nodma_base, nodma_size; +} _lt_memory_regions; + + +/* + * misc. data that needs to be measured along with the hypervisor because + * it affects hypervisor security + * more items may be added over time + * we need to give it a default value to prevent it from being in bss + */ +#define MAX_XEN_CMD_LINE 1024 +static struct misc_measured_data_t { + char cmdline[MAX_XEN_CMD_LINE]; +} _misc_measured_data = {""}; + + +/* clear processor state of any secrets */ +void smx_scrub_proc(void) +{ + /* only scrub if we setup the environment */ + if ( _senter_start != 1 ) + return; + + /* we don't have any secrets to clear, however */ + ; +} + +void smx_scrub_mem(void) +{ + /* only peform mem scrub if we setup the environment */ + if ( _senter_start != 1 ) + return; + + /* scrub any secrets by clearing the memory */ + /* we don't have any secrets to scrub, however */ + ; + + /* flush chipset caches and buffers */ + write_priv_config_reg(LTCR_LT_CMD_FLUSH_WB, 0x01); + printk("SMX: memory scubbed\n"); + + /* TBD: cap dynamic PCRs (17, 18) */ + + /* set LT.CMD.NO-SECRETS flag */ + write_priv_config_reg(LTCR_LT_CMD_NO_SECRETS, 0x01); + read_priv_config_reg(LTCR_LT_E2STS); /* just a fence, so ignore return */ + printk("SMX: secrets flag cleared\n"); + + /* close LT private config space */ + read_priv_config_reg(LTCR_LT_E2STS); /* fence */ + write_priv_config_reg(LTCR_LT_CMD_CLOSE_PRIVATE, 0x01); + read_pub_config_reg(LTCR_LT_E2STS); /* fence */ + printk("SMX: private config space closed\n"); +} + +void smx_teardown(void) +{ + /* only peform teardown if we setup the environment */ + if ( _senter_start != 1 ) + return; + + /* call GETSEC[SEXIT] */ + __getsec_sexit(); + printk("SMX: GETSEC[SEXIT] protected environment torn down\n"); + + /* since we've torn down the environment, clear the _senter_start flag */ + _senter_start = -1; +} + +static void dump_sinit_mdrs(lt_heap_data_hdr_t *lt_heap_data_hdr) +{ + sinit_mvmm_data_v1_t *sinit_mvmm_data; + sinit_mdr_t *mdr; + int i; + static char *mem_types[] = {"GOOD", "SMM OVERLAY", "SMM NON-OVERLAY", + "PCIE CONFIG SPACE", "PROTECTED"}; + + if ( lt_heap_data_hdr->version != 0x01 ) { + printk("SMX: SINIT to MVMM data version incompatible (%x)\n", + lt_heap_data_hdr->version); + return; + } + + sinit_mvmm_data = (sinit_mvmm_data_v1_t *)lt_heap_data_hdr; + + for ( i = 0; i < sinit_mvmm_data->num_mdrs; i++ ) { + mdr = sinit_mvmm_data->mdrs + i; + printk("SMX: mdr[%d] :\n", i); + printk("SMX: \tstart = %08x:%08x\n", mdr->start_hi, mdr->start_lo); + printk("SMX: \tlength = %x%x\n", mdr->length_hi, mdr->length_lo); + if ( mdr->mem_type < sizeof(mem_types)/sizeof(mem_types[0]) ) + printk("SMX: \tmem_type = %s\n", mem_types[mdr->mem_type]); + else + printk("SMX: \tmem_type = %d\n", (int)mdr->mem_type); + } +} + +static int insert_after_region(struct e820map *e820, int pos, + uint64_t addr, uint64_t size, + uint32_t type) +{ + int i; + + /* no more room */ + if ( e820->nr_map + 1 >= E820MAX ) + return -1; + + /* shift (copy) everything up one entry */ + for (i = e820->nr_map - 1; i > pos; i--) + e820->map[i+1] = e820->map[i]; + + /* now add our entry */ + e820->map[pos+1].addr = addr; + e820->map[pos+1].size = size; + e820->map[pos+1].type = type; + + e820->nr_map++; + + return 0; +} + +static void remove_region(struct e820map *e820, int pos) +{ + int i; + + /* shift (copy) everything down one entry */ + for (i = pos; i < e820->nr_map - 1; i++) + e820->map[i] = e820->map[i+1]; + + e820->nr_map--; +} + +static int separate_region(struct e820map *e820, uint64_t new_addr, + uint64_t new_size) +{ + int i; + uint64_t addr, size; + uint32_t type; + + if ( new_size == 0 ) + return 0; + + /* find where our region belongs in the table and insert it */ + for (i = 0; i < e820->nr_map; i++) { + addr = e820->map[i].addr; + size = e820->map[i].size; + type = e820->map[i].type; + /* is our region at the beginning of the current map region? */ + if ( new_addr == addr ) { + if ( insert_after_region(e820, i-1, new_addr, new_size, + E820_PROTECTED) == -1 ) + return -1; + break; + } + /* are we w/in the current map region? */ + else if ( new_addr > addr && new_addr < (addr + size) ) { + if ( insert_after_region(e820, i, new_addr, new_size, + E820_PROTECTED) == -1 ) + return -1; + /* fixup current region */ + e820->map[i].size = new_addr - e820->map[i].addr; + i++; /* adjust to always be that of our region */ + /* insert a copy of current region (before adj) after us so */ + /* that rest of code can be common with previous case */ + if ( insert_after_region(e820, i, addr, size, type) == -1 ) + return -1; + break; + } + /* is our region in a gap in the map? */ + else if ( addr > new_addr ) { + if ( insert_after_region(e820, i-1, new_addr, new_size, + E820_PROTECTED) == -1 ) + return -1; + break; + } + } + /* if we reached the end of the map without finding an overlapping */ + /* region, insert us at the end (note that this test won't trigger */ + /* for the second case above because the insert() will have incremented */ + /* nr_map and so i++ will still be less) */ + if ( i == e820->nr_map ) { + if ( insert_after_region(e820, i-1, new_addr, new_size, + E820_PROTECTED) == -1 ) + return -1; + return 0; + } + + i++; /* move to entry after our inserted one (we're not at end yet) */ + + /* did we split the (formerly) previous region? */ + if ( (new_addr >= e820->map[i].addr) && + ((new_addr + new_size) < (e820->map[i].addr + e820->map[i].size)) ) { + /* then adjust the current region (adj size first) */ + e820->map[i].size = (e820->map[i].addr + e820->map[i].size) - + (new_addr + new_size); + e820->map[i].addr = new_addr + new_size; + return 0; + } + + /* if our region completely covers any existing regions, delete them */ + while ( (i < e820->nr_map) && ((new_addr + new_size) >= + (e820->map[i].addr + e820->map[i].size)) ) + remove_region(e820, i); + + /* finally, if our region partially overlaps an existing region, */ + /* then truncate the exiting region */ + if ( (i < e820->nr_map) && ((new_addr + new_size) > e820->map[i].addr) ) + e820->map[i].addr = new_addr + new_size; + + return 0; +} + +int smx_reserve_memory(struct e820map *e820) +{ + struct lt_memory_regions_t *lt_mem_regions; + u64 base, size; + lt_heap_t *lt_heap; + lt_heap_data_hdr_t *lt_heap_data_hdr; + + /* + * LT has three regions of RAM that need to be reserved for use by only the + * hypervisor; not even dom0 should have access: + * LT heap, SINIT AC module, NoDMA table + */ + + lt_mem_regions = (struct lt_memory_regions_t *)&_lt_memory_regions; + + /* LT heap */ + base = lt_mem_regions->heap_base; + size = lt_mem_regions->heap_size; + printk("SMX: protecting LT heap (%Lx - %Lx) in e820 table\n", base, + (base + size - 1)); + if ( separate_region(e820, base, size) == -1 ) + return -1; + + /* SINIT */ + base = lt_mem_regions->sinit_base; + size = lt_mem_regions->sinit_size; + printk("SMX: protecting SINIT (%Lx - %Lx) in e820 table\n", base, + (base + size - 1)); + if ( separate_region(e820, base, size) == -1 ) + return -1; + + /* NoDMA table */ + base = lt_mem_regions->nodma_base; + size = lt_mem_regions->nodma_size; + printk("SMX: protecting NoDMA table (%Lx - %Lx) in e820 table\n", base, + (base + size - 1)); + if ( separate_region(e820, base, size) == -1 ) + return -1; + + /* TBD: we will need to parse sinit_mvmm_data.mdrs records and ensure */ + /* that we don't use inappropriate memory for domains */ + /* (we can't use get_heap() because fixmap isn't setup yet) */ + lt_heap = (lt_heap_t *)(unsigned long)lt_mem_regions->heap_base; + lt_heap_data_hdr = get_sinit_mvmm_data_start(lt_heap); + dump_sinit_mdrs(lt_heap_data_hdr); + + return 0; +} + +/* put after teardown fns because those use std printk() */ +#undef printk +#ifdef DEBUG_SMX +#define printk early_serial_printk +#else +#define printk(_f , _a...) /**/ +#endif + + +bool smx_in_prot_env(void) +{ + return (_senter_start != 1) ? false : true; +} + +u32 config_reg_base_addr(u32 base_phys) +{ + unsigned long cr0; + int idx; + + cr0 = read_cr0(); + + /* if paging has been enabled then must use fixmap */ + if ( cr0 & X86_CR0_PG ) { + idx = (base_phys - LT_PUB_CONFIG_REGS_BASE) >> PAGE_SHIFT; + return fix_to_virt(FIX_LT_PUB_CONFIG_REGS_BASE + idx); + } + /* else can use physical addr directly */ + else + return base_phys; +} + +/* + * sets up LT heap + */ +static lt_heap_t *setup_lt_heap(void *ptab_base) +{ + lt_heap_t *lt_heap; + os_mvmm_data_v1_t *os_mvmm_data; + os_sinit_data_v1_t *os_sinit_data; + + lt_heap = get_lt_heap(); + + /* + * BIOS to OS/loader data already setup by BIOS + */ + + /* + * OS/loader to MVMM data + */ + os_mvmm_data = (os_mvmm_data_v1_t *)get_os_mvmm_data_start(lt_heap); + *get_data_size_addr(os_mvmm_data) = sizeof(*os_mvmm_data) + sizeof(u64); + memset(os_mvmm_data, 0, sizeof(*os_mvmm_data)); + os_mvmm_data->version = 0x01; + + /* + * OS/loader to SINIT data + */ + os_sinit_data = (os_sinit_data_v1_t *)get_os_sinit_data_start(lt_heap); + *get_data_size_addr(os_sinit_data) = sizeof(*os_sinit_data) + sizeof(u64); + memset(os_sinit_data, 0, sizeof(*os_sinit_data)); + os_sinit_data->version = 0x01; + /* this is phys addr */ + os_sinit_data->mvmm_ptab_lo = (u32)ptab_base; + os_sinit_data->mvmm_ptab_hi = 0; + os_sinit_data->mvmm_size_lo = (u32)__pa(&_end) - (u32)__pa(&_text); + os_sinit_data->mvmm_size_hi = 0; + /* this is linear addr (offset from MVMM base) of mvmm header */ + os_sinit_data->mvmm_hdr_base_lo = (u32)&_mvmm_hdr - (u32)&_text; + os_sinit_data->mvmm_hdr_base_hi = 0; + + /* + * SINIT to MVMM data will be setup by SINIT + */ + + return lt_heap; +} + +/* MVMM page table can only contain 4k pages */ +#define MVMM_PAGE_SHIFT 12 +#define MVMM_PAGE_SIZE (1L << PAGE_SHIFT) +#define MVMM_PAGE_MASK (~(PAGE_SIZE-1)) + +/* LT uses PAE format page table for MVMM page table */ +typedef u64 mvmm_pfn_t; + +#define MVMM_NUM_PTES (MVMM_PAGE_SIZE / sizeof(mvmm_pfn_t)) + +/* page dir/table entry is phys addr + P + R/W + PWT */ +#define MVMM_MAKE_PDTE(addr) (((u64)(unsigned long)addr & MVMM_PAGE_MASK) \ + | 0x01) + +/* page directory/table */ +typedef struct { + mvmm_pfn_t pdtes[MVMM_NUM_PTES]; +} mvmm_pg_dirtab_t; + +/* MVMM page table */ +typedef struct { + mvmm_pfn_t pg_dir_ptr[4]; +} mvmm_ptab_t; + +static void *build_mvmm_pagetable(multiboot_info_t *mbi) +{ + void *mvmm_addr, *mvmm_end; + void *next_ptab_pg; /* page to use for next page dir or page table */ + mvmm_ptab_t *ptab_base; + u32 ptab_size, mvmm_size; + mvmm_pfn_t *pde, *pte; + mvmm_pg_dirtab_t *pd, *pt; + struct misc_measured_data_t *misc_data; + + /* + * requirements of MVMM page tables: + * - must be in PAE format + * - 4k pages + * - breadth-first traversal must have increasing phys addrs + * - all addrs must be: <640k or >1M, not overlap w/ device mem, 4GB */ + if ( (unsigned long)mvmm_end > 0xffffffff ) { + printf("SMX: MVMM is above 4GB which is not permitted\n"); + return NULL; + } + + /* make copy of misc. data that needs to be measured */ + misc_data = (struct misc_measured_data_t *)__pa(&_misc_measured_data); + memset(misc_data->cmdline, 0, MAX_XEN_CMD_LINE); + strncpy( misc_data->cmdline, (char *)mbi->cmdline, MAX_XEN_CMD_LINE-1); + + /* calculate size needed for page table */ + ptab_size = (mvmm_size >> MVMM_PAGE_SHIFT) /* # pages = # pte's */ + * sizeof(mvmm_pfn_t) /* => size of pte's */ + + MVMM_PAGE_SIZE /* + 1 page dir */ + + MVMM_PAGE_SIZE; /* + page dir ptr table */ + /* round up to nearest page */ + ptab_size = (ptab_size + MVMM_PAGE_SIZE) & MVMM_PAGE_MASK; + + /* place ptab_base below BAD_MVMM_MEM_LO */ + ptab_base = (void *)((BAD_MVMM_MEM_LO - ptab_size) & MVMM_PAGE_MASK); + + memset(ptab_base, 0, MVMM_PAGE_SIZE); + printk("SMX: ptab_size=%x, ptab_base=%p\n", ptab_size, ptab_base); + + /* only 1 page dir */ + pd = (void *)ptab_base + MVMM_PAGE_SIZE; + memset(pd, 0, MVMM_PAGE_SIZE); + + /* only use first entry in page dir ptr table */ + ptab_base->pg_dir_ptr[0] = MVMM_MAKE_PDTE(pd); + /* printk("SMX: pg_dir_ptr[0]=%Lx, pd=%p\n", ptab_base->pg_dir_ptr[0], + pd); */ + + next_ptab_pg = (void *)pd + MVMM_PAGE_SIZE; + + /* outer loop is page dir (will break when reach end of MVMM) */ + for ( pde = pd->pdtes; pde < (pd->pdtes + MVMM_PAGE_SIZE); pde++ ) { + pt = next_ptab_pg; + memset(pt, 0, MVMM_PAGE_SIZE); + + next_ptab_pg += PAGE_SIZE; + + *pde = MVMM_MAKE_PDTE(pt); + /* printk("SMX: *pde=%Lx, pt=%p\n", *pde, pt); */ + + /* inner loop is page table (will break when reach end of MVMM) */ + for ( pte = pt->pdtes; pte < (pt->pdtes + MVMM_PAGE_SIZE); pte++ ) { + *pte = MVMM_MAKE_PDTE(mvmm_addr); + /* printk("SMX: *pte=%Lx, mvmm_addr=%p\n", *pte, mvmm_addr); */ + + mvmm_addr += PAGE_SIZE; + + /* last page added to table, so exit all loops */ + if ( mvmm_addr >= mvmm_end ) + goto table_done; + } + } + printk("SMX: MVMM size exceeded page table size--not possible!\n"); + return NULL; + + table_done: + return ptab_base; +} + +/* + * Verify that processor is LT-capable and enabled. + * Do some processor-related sanity checks here before calling SENTER + * because any violations will cause an LT.RESET. Instead detect these, + * print a desriptive message, and skip LT protected launch. + */ +static int verify_processor_state(void) +{ + unsigned long eflags; + unsigned long cr0, cr4; + u32 eax, edx; + unsigned int cpu_capability[NCAPINTS]; + capabilities_t cap; + lt_sts_t sts; + u64 mcg_cap, mcg_stat; + int i; + + /* + * verify processor is capable of SMX + */ + /* Xen only fills x86_capability word 0 */ + cpu_capability[4] = cpuid_ecx(1); + if ( !(test_bit(X86_FEATURE_SMXE, cpu_capability)) ) { + printk("SMX: CPU does not support SMX\n"); + return -1; + } + + printk("SMX: processor is SMX-capable\n"); + + /* no need to verify VMX capability at this time */ + + /* + * ensure that SMX is enabled by feature control MSR + * + * enable VMX after SMX but disable VMX outside of SMX + * - this is most secure launch since it prevents full (transparent) + * virtualzation if LT launch is disabled or fails + * - BIOS or bootloader should really have set and locked it + */ + + rdmsr(IA32_FEATURE_CONTROL_MSR, eax, edx); + + if ( eax & IA32_FEATURE_CONTROL_MSR_LOCK ) { + printk("SMX: IA32_FEATURE_CONTROL_MSR is locked (%x)\n", eax); + printk("SMX: \tIA32_FEATURE_CONTROL_MSR_ENABLE_VMX_IN_SMX=%d\n", + (eax & IA32_FEATURE_CONTROL_MSR_ENABLE_VMX_IN_SMX) ? 1 : 0); + printk("SMX: \tIA32_FEATURE_CONTROL_MSR_ENABLE_VMX_OUT_SMX=%d\n", + (eax & IA32_FEATURE_CONTROL_MSR_ENABLE_VMX_OUT_SMX) ? 1 : 0); + if ( (eax & IA32_FEATURE_CONTROL_MSR_ENABLE_SENTER) == 0x00 ) { + printk("SMX: SENTER disabled by feature control MSR\n"); + return -1; + } + } + else { + printk("SMX: IA32_FEATURE_CONTROL_MSR_LOCK is not locked (%x)\n", eax); + /* + * for testing purposes we enable VMX outside of SMX as well so that + * if there was some error in the LT boot, VMX will continue to work + */ + /* eax &= ~(u32)IA32_FEATURE_CONTROL_MSR_ENABLE_VMX_OUT_SMX; */ + eax |= IA32_FEATURE_CONTROL_MSR_ENABLE_VMX_IN_SMX | + IA32_FEATURE_CONTROL_MSR_ENABLE_VMX_OUT_SMX | + IA32_FEATURE_CONTROL_MSR_ENABLE_SENTER | + IA32_FEATURE_CONTROL_MSR_SENTER_PARAM_CTL | + IA32_FEATURE_CONTROL_MSR_LOCK; + wrmsr(IA32_FEATURE_CONTROL_MSR, eax, 0); + printk("SMX: IA32_FEATURE_CONTROL_MSR set to %x\n", eax); + } + + /* + * check that not in VMX mode + */ + cr4 = read_cr4(); + printk("SMX: cr4=%lx\n", cr4); + if ( cr4 & X86_CR4_VMXE ) { + printk("SMX: already in VMX mode\n"); + return -1; + } + + /* + * enable SMX + */ + + write_cr4(cr4 | X86_CR4_SMXE); + /* set_in_cr4() would normally do this but it won't work properly + * until paging is enabled, so set this manually + * this is needed because cr4 will get re-set to it by x86_32.S + */ + *((unsigned long*)__pa(&mmu_cr4_features)) |= X86_CR4_SMXE; + + printk("SMX: SMX is enabled\n"); + + /* + * verify that an LT-capable chipset is present and + * check that all needed SMX capabilities are supported + */ + + cap = __getsec_capabilities(0); + if ( !cap.chipset_present ) { + printk("SMX: LT chipset not present\n"); + return -1; + } + if ( !(cap.senter && cap.sexit && cap.parameters && cap.smctrl + && cap.wakeup) ) { + printk("SMX: insufficient SMX capabilities (%x)\n", cap._raw); + return -1; + } + + printk("SMX: LT chipset and all needed capabilities present\n"); + + /* + * verify/set cr0 and EFLAGS pre-conditions for GETSEC[SENTER] + */ + + cr0 = read_cr0(); + printk("SMX: cr0=%lx\n", cr0); + + /* must be in protected mode (CR0.PE=1) */ + if ( !(cr0 & X86_CR0_PE) ) { + printk("SMX: CR0.PE not set\n"); + cr0 |= X86_CR0_PE; + } + + /* cache must be enabled */ + if ( cr0 & X86_CR0_CD ) { + printk("SMX: CR0.CD set\n"); + cr0 &= ~X86_CR0_CD; + } + if ( cr0 & X86_CR0_NW ) { + printk("SMX: CR0.NW set\n"); + cr0 &= ~X86_CR0_NW; + } + + /* native FPU error reporting must be enabled for proper */ + /* interaction behavior */ + if ( !(cr0 & X86_CR0_NE) ) { + printk("SMX: CR0.NE not set\n"); + cr0 |= X86_CR0_NE; + } + + write_cr0(cr0); + + /* cannot be in virtual-8086 mode (EFLAGS.VM=1) */ + __save_flags(eflags); + if ( eflags & X86_EFLAGS_VM ) { + printk("SMX: EFLAGS.VM set\n"); + __restore_flags(eflags | X86_EFLAGS_VM); + } + + printk("SMX: CR0 and EFLAGS OK\n"); + + /* + * verify that we're not already in a protected environment + */ + sts = (lt_sts_t)read_pub_config_reg(LTCR_LT_STS); + if ( sts.senter_done_sts ) { + printk("SMX: already in protected environment\n"); + return -1; + } + + /* + * verify all machine check status registers are clear + */ + + /* no machine check in progress (IA32_MCG_STATUS.MCIP=1)*/ + rdmsrl(MSR_IA32_MCG_STATUS, mcg_stat); + if ( mcg_stat & 0x04 ) { + printk("SMX: machine check in progress\n"); + return -1; + } + + /* all machine check regs are clear */ + rdmsrl(MSR_IA32_MCG_CAP, mcg_cap); + for (i = 0; i < (mcg_cap & 0xff); i++) { + rdmsrl(MSR_IA32_MC0_STATUS + 4*i, mcg_stat); + if ( mcg_stat & (1ULL << 63) ) { + printk("SMX: MCG[%d] = %Lx ERROR\n", i, mcg_stat); + return -1; + } + } + + printk("SMX: no machine check errors\n"); + + /* all is well with the processor state */ + printk("SMX: verify_processor_state() passed\n"); + + return 0; +} + +/* + * Restore previous MTRRs and do other cleanup stuff here + * + * @return multiboot_info_t structure for use by Xen + */ +multiboot_info_t* restore_os_state(void) +{ + multiboot_info_t *mbi; + lt_heap_t *lt_heap; + os_mvmm_data_v1_t *os_mvmm_data; + struct lt_memory_regions_t *lt_mem_regions; + + printk("SMX: restoring OS state\n"); + + /* clear error config registers so that we start fresh */ + write_priv_config_reg(LTCR_LT_CRASH, 0x00000000); + write_priv_config_reg(LTCR_LT_ESTS, 0xffffffff); /* write 1's to clear */ + + /* save the LT memory regions info for use in fixing-up e820 map */ + lt_mem_regions = (struct lt_memory_regions_t *)__pa(&_lt_memory_regions); + lt_mem_regions->heap_base = read_pub_config_reg(LTCR_LT_HEAP_BASE); + lt_mem_regions->heap_size = read_pub_config_reg(LTCR_LT_HEAP_SIZE); + lt_mem_regions->sinit_base = read_pub_config_reg(LTCR_LT_SINIT_BASE); + lt_mem_regions->sinit_size = read_pub_config_reg(LTCR_LT_SINIT_SIZE); + lt_mem_regions->nodma_base = read_pub_config_reg(LTCR_LT_NODMA_BASE); + /* size encoding is 0=128k, 1=256k, 2=512k, ... = 128k*2^val, so convert */ + lt_mem_regions->nodma_size = read_pub_config_reg(LTCR_LT_NODMA_SIZE); + lt_mem_regions->nodma_size = 0x20000ULL << lt_mem_regions->nodma_size; + + /* get saved OS state (os_mvmm_data_t) from LT heap */ + lt_heap = get_lt_heap(); + os_mvmm_data = (os_mvmm_data_v1_t *)get_os_mvmm_data_start(lt_heap); + + /* restore pre-SENTER MTRRs that were overwritten for SINIT launch */ + restore_mtrrs(&(os_mvmm_data->saved_mtrr_state)); + + /* enable SMIs */ + __getsec_smctrl(); + + /* always set the LT.CMD.SECRETS flag */ + /* TBD: we really don't have any secrets yet, so we could skip this */ + /* or we could provide an API to allow domains to set it if they have */ + /* secrets */ + write_priv_config_reg(LTCR_LT_CMD_SECRETS, 0x01); + read_priv_config_reg(LTCR_LT_E2STS); /* just a fence, so ignore return */ + printk("SMX: set LT.CMD.SECRETS flag\n"); + + /* restore mbi */ + mbi = os_mvmm_data->mbi; + + /* copy back the command line that we saved and measured */ + strcpy((char *)mbi->cmdline, ((struct misc_measured_data_t *) + __pa(&_misc_measured_data))->cmdline); + + /* decrement module count so that SINIT is not counted as Dom0's initrd */ + mbi->mods_count--; + + /* __start is expecting mbi to be virt addr, so convert it */ + mbi = (multiboot_info_t *)__va(mbi); + + /* push mbi onto the stack so that it can be restored to ebx */ + return mbi; +} + +static void *copy_sinit(void *src_base, u32 src_size) +{ + void *dest_base; + u32 dest_size; + acm_hdr_t *acm_hdr; + lt_heap_t *lt_heap; + lt_heap_data_hdr_t *lt_heap_data_hdr; + bios_os_data_v0_t *bios_os_data; + + /* get BIOS-reserved region from LT.SINIT.BASE config reg */ + dest_base = (void *)(unsigned long)read_pub_config_reg(LTCR_LT_SINIT_BASE); + dest_size = (u32)read_pub_config_reg(LTCR_LT_SINIT_SIZE); + + /* make sure it fits */ + if ( dest_size < src_size ) { + printk("SMX: BIOS-reserved SINIT size (%x) is too small for loaded " + "SINIT (%x)\n", dest_size, src_size); + return NULL; + } + + /* check size of loaded module against internal size */ + acm_hdr = (acm_hdr_t *)src_base; + if ( (acm_hdr->size * 4) != src_size ) { + printk("SMX: loaded SINIT size (%x) not same as internal size (%x)\n", + src_size, acm_hdr->size); + return NULL; + } + + /* check if BIOS already loaded an SINIT module there */ + /* (but replace it even if it has been loaded) */ + lt_heap = get_lt_heap(); + lt_heap_data_hdr = get_bios_os_data_start(lt_heap); + if ( lt_heap_data_hdr->version != 0x00 ) { + printk("SMX: BIOS to OS data version incompatible (%x)\n", + lt_heap_data_hdr->version); + return NULL; + } + bios_os_data = (bios_os_data_v0_t *)lt_heap_data_hdr; + if ( bios_os_data->bios_sinit_size != 0 ) { + printk("SMX: BIOS has already loaded an SINIT module\n"); + dump_acm_hdr(dest_base, (const char *)__pa("BIOS SINIT")); + /* assume our SINIT is newer and replace BIOS's */ + } + + memcpy(dest_base, src_base, src_size); + + printk("SMX: copied SINIT (size=%x) to %p\n", src_size, dest_base); + + return dest_base; +} + +multiboot_info_t* start_smx(multiboot_info_t *mbi) +{ + module_t *sinit_mod; + void *sinit_base; + u32 sinit_size; + lt_heap_t *lt_heap; + os_mvmm_data_v1_t *os_mvmm_data; + void *mvmm_ptab_base; + mvmm_hdr_t *mvmm_hdr; + multiboot_info_t *virt_mbi; + + /* + * check if this is being called as part of the SENTER re-start and + * if so, call restore_os_state() + */ + if ( *((int *)__pa(&_senter_start)) == 1 ) + return restore_os_state(); + + /* clear SENTER flag */ + *((int *)__pa(&_senter_start)) = -1; + + printk("SMX: start_smx()\n"); + + /* check if there was an error on last boot and print it */ + display_errors(); + + /* the mbi we get is adjusted to be at virt addr, so covert back to phys */ + virt_mbi = mbi; + mbi = (multiboot_info_t *)__pa(mbi); + + /* check that we have at least one multiboot module - SINIT */ + if ( !(mbi->flags & MBI_MODULES) || (mbi->mods_count == 0) ) { + printk("SMX: no SINIT module provided\n"); + return virt_mbi; + } + + /* verify the processor is LT capable and enabled */ + if ( verify_processor_state() == -1 ) + return virt_mbi; + + /* + * copy SINIT to memory reserved for it by BIOS + */ + /* expect SINIT to be last of GRUB modules */ + sinit_mod = (module_t *)(mbi->mods_addr); + sinit_base = (void *)sinit_mod[mbi->mods_count-1].mod_start; + sinit_size = sinit_mod[mbi->mods_count-1].mod_end - + (unsigned long)sinit_base; + /* check if this is really an SINIT AC module */ + if ( !is_acmod(sinit_base) ) { + printk("SMX: could not find SINIT AC module\n"); + return virt_mbi; + } + /* copy it */ + sinit_base = copy_sinit(sinit_base, sinit_size); + if ( sinit_base == NULL ) + return virt_mbi; + + /* verify things are nominally OK */ + if ( (verify_acmod(sinit_base) == -1) || + (verify_tpm_ready() == -1) ) + return virt_mbi; + + /* set the MVMM entry point in the MVMM header */ + /* entry point is relative to beginning of MVMM */ + mvmm_hdr = (mvmm_hdr_t *)__pa(&_mvmm_hdr); + mvmm_hdr->entry_point = (u32)__pa(&__start) - (u32)__pa(&_text); + printk("SMX: MVMM entry point = %x\n", mvmm_hdr->entry_point); + + /* create MVMM page table */ + mvmm_ptab_base = build_mvmm_pagetable(mbi); + if ( mvmm_ptab_base == NULL ) + return virt_mbi; + + /* setup LT heap */ + lt_heap = setup_lt_heap(mvmm_ptab_base); + os_mvmm_data = (os_mvmm_data_v1_t *)get_os_mvmm_data_start(lt_heap); + + /* save mbi */ + os_mvmm_data->mbi = mbi; + + /* save MTRRs before we alter them for SINIT launch */ + save_mtrrs(&(os_mvmm_data->saved_mtrr_state)); + + /* set MTRRs properly for AC module (SINIT) */ + set_mtrrs_for_acmod(sinit_base, sinit_size); + + /* set flag that we're about to do SENTER */ + *((int *)__pa(&_senter_start)) = 1; + + printk("SMX: executing GETSEC[SENTER]...\n"); + __getsec_senter((u32)sinit_base, sinit_size); + printk("SMX: ERROR--we should not get here!\n"); + return virt_mbi; +} + + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r 765b7e23d979 -r 843be4e340c8 xen/arch/x86/smx/tpm.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/x86/smx/tpm.c Fri Sep 01 18:28:21 2006 +0800 @@ -0,0 +1,164 @@ +/* + * tpm.c: TPM-related support functions for LT + * + * Copyright (c) 2003-2006, 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 + + +#define DEBUG_SMX 1 + +#undef printk +#ifdef DEBUG_SMX +#define printk early_serial_printk +#else +#define printk(_f , _a...) /**/ +#endif + +/* + * TPM registers and data structures + * + * register values are offsets from each locality base + * see {read,write}_tpm_reg() for data struct format + */ + +/* TPM_ACCESS_x */ +#define TPM_REG_ACCESS 0x00 +typedef union { + u8 _raw[1]; /* 1-byte reg */ + struct { + u8 tpm_establishment : 1; /* RO, 0=T/OS has been established + before */ + u8 request_use : 1; /* RW, 1=locality is requesting TPM use */ + u8 pending_request : 1; /* RO, 1=other locality is requesting + TPM usage */ + u8 seize : 1; /* WO, 1=seize locality */ + u8 been_seized : 1; /* RW, 1=locality seized while active */ + u8 active_locality : 1; /* RW, 1=locality is active */ + u8 reserved : 1; + u8 tpm_reg_valid_sts : 1; /* RO, 1=other bits are valid */ + } __attribute__ ((packed)); +} tpm_reg_access_t; + +/* TPM_STS_x */ +#define TPM_REG_STS 0x18 +typedef union { + u8 _raw[3]; /* 3-byte reg */ + struct { + u8 reserved1 : 1; + u8 response_retry : 1; /* WO, 1=re-send response */ + u8 reserved2 : 1; + u8 expect : 1; /* RO, 1=more data for command expected */ + u8 data_avail : 1; /* RO, 0=no more data for response */ + u8 tpm_go : 1; /* WO, 1=execute sent command */ + u8 command_ready : 1; /* RW, 1=TPM ready to receive new cmd */ + u8 sts_valid : 1; /* RO, 1=data_avail and expect bits are + valid */ + u16 burst_count : 16; /* RO, # read/writes bytes before wait */ + } __attribute__ ((packed)); +} tpm_reg_sts_t; + +/* + * assumes that all reg types follow above format: + * - packed + * - member named '_raw' which is array whose size is that of data to read + */ +#define read_tpm_reg(locality, reg, pdata) \ + _read_tpm_reg(locality, reg, (pdata)->_raw, sizeof(*(pdata))) + +#define write_tpm_reg(locality, reg, pdata) \ + _write_tpm_reg(locality, reg, (pdata)->_raw, sizeof(*(pdata))) + + +static void _read_tpm_reg(int locality, u32 reg, u8 *_raw, size_t size) +{ + size_t i; + for ( i = 0; i < size; i++ ) + _raw[i] = readb((TPM_LOCALITY_BASE_N(locality) | reg) + i); +} + +static void _write_tpm_reg(int locality, u32 reg, u8 *_raw, size_t size) +{ + size_t i; + for ( i = 0; i < size; i++ ) + writeb(_raw[i], (TPM_LOCALITY_BASE_N(locality) | reg) + i); +} + + +/* ensure TPM is ready to accept commands */ +int verify_tpm_ready() +{ + tpm_reg_access_t reg_acc; + tpm_reg_sts_t reg_sts; + + /* + * must ensure TPM_ACCESS_0.activeLocality bit is clear + * (: locality is not active) + */ + read_tpm_reg(0, TPM_REG_ACCESS, ®_acc); + if ( reg_acc.active_locality != 0 ) { + /* make inactive by writing a 1 */ + reg_acc.active_locality = 1; + write_tpm_reg(0, TPM_REG_ACCESS, ®_acc); + } + + /* + * read TPM status register to check if it is ready to accept a command + * we can do this for locality 2 and assume same for other localities + * we will not wait on it--if it is not ready then error + */ + read_tpm_reg(2, TPM_REG_STS, ®_sts); + if ( !reg_sts.command_ready ) { + printk("SMX: TPM is not ready for commands\n"); + return -1; + } + + printk("SMX: TPM is ready\n"); + + return 0; +} + + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r 765b7e23d979 -r 843be4e340c8 xen/include/asm-x86/smx/acmod.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/include/asm-x86/smx/acmod.h Fri Sep 01 18:28:21 2006 +0800 @@ -0,0 +1,88 @@ +/* + * acmod.h: LT Authenticated Code (AC) Modules -related definitions + * + * Copyright (c) 2003-2006, 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 __ASM_X86_SMX_ACMOD_H__ +#define __ASM_X86_SMX_ACMOD_H__ + +#include + +/* + * authenticated code (AC) module header (ver 0.0) + */ + +typedef struct { + u32 module_type; + u32 header_len; + u32 header_ver; + u32 module_id; + u32 module_vendor; + u32 date; + u32 size; + u32 reserved1; + u32 code_control; + u32 error_entry_point; + u32 gdt_limit; + u32 gdt_base; + u32 seg_sel; + u32 entry_point; + u8 reserved2[64]; + u32 key_size; + u32 scratch_size; + u8 rsa2048_pubkey[256]; + u32 pub_exp; + u8 rsa2048_sig[256]; + u32 scratch[143]; + u8 user_area[]; +} acm_hdr_t; + +/* value of mod_type field for valid AC module */ +#define ACM_VALID_MOD_TYPE 0x02 + +extern void dump_acm_hdr(acm_hdr_t *hdr, const char *mod_name); +extern int verify_acmod(void *acmod_base); +extern int set_mtrrs_for_acmod(void *acmod_base, u32 acmod_size); +extern int is_acmod(void *acmod_base); + +#endif /* __ASM_X86_SMX_ACMOD_H__ */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r 765b7e23d979 -r 843be4e340c8 xen/include/asm-x86/smx/config_regs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/include/asm-x86/smx/config_regs.h Fri Sep 01 18:28:21 2006 +0800 @@ -0,0 +1,189 @@ +/* + * mtrrs.c: LT configuration register -related definitions + * + * Copyright (c) 2003-2006, 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 __ASM_X86_SMX_CONFIG_REGS_H__ +#define __ASM_X86_SMX_CONFIG_REGS_H__ + +/* + * LT configuration registers (offsets from LT_{PUB, PRIV}_CONFIG_REGS_BASE) + */ + +#define LT_PUB_CONFIG_REGS_BASE 0xfed30000 +#define LT_PRIV_CONFIG_REGS_BASE 0xfed20000 + +/* # pages for each config regs space - used by fixmap */ +#define NR_LT_CONFIG_PAGES ((LT_PUB_CONFIG_REGS_BASE - \ + LT_PRIV_CONFIG_REGS_BASE) >> \ + PAGE_SHIFT) + +#define LTCR_LT_STS 0x0000 +#define LTCR_LT_ESTS 0x0008 +#define LTCR_LT_CRASH 0x0030 +#define LTCR_LT_CMD_SYS_RESET 0x0038 +#define LTCR_LT_CMD_OPEN_PRIVATE 0x0040 +#define LTCR_LT_CMD_CLOSE_PRIVATE 0x0048 +#define LTCR_LT_CMD_FLUSH_WB 0x0258 +#define LTCR_LT_NODMA_BASE 0x0260 +#define LTCR_LT_NODMA_SIZE 0x0268 +#define LTCR_LT_SINIT_BASE 0x0270 +#define LTCR_LT_SINIT_SIZE 0x0278 +#define LTCR_LT_MVMM_JOIN 0x0290 +#define LTCR_LT_HEAP_BASE 0x0300 +#define LTCR_LT_HEAP_SIZE 0x0308 +#define LTCR_LT_CMD_SECRETS 0x08e0 +#define LTCR_LT_CMD_NO_SECRETS 0x08e8 +#define LTCR_LT_E2STS 0x08f0 + +/* + * format of LT.CRASH register + */ +typedef union { + u64 _raw; + struct { + u64 type : 15; /* src-specific error code */ + u64 src : 1; /* 0=AC module */ + u64 reserved : 14; + u64 external : 1; /* 0=from proc, 1=from external SW */ + u64 valid : 1; /* 1=valid */ + }; +} lt_crash_t; + +/* + * format of LT.ESTS register + */ +typedef union { + u64 _raw; + struct { + u64 reserved1 : 1; + u64 lt_rogue_sts : 1; + u64 bm_write_attack : 1; + u64 bm_read_attack : 1; + u64 fsb_write_attack : 1; + u64 fsb_read_attack : 1; + u64 lt_wake_error_sts : 1; + u64 reserved2 : 1; + }; +} lt_ests_t; + +/* + * format of LT.E2STS register + */ +typedef union { + u64 _raw; + struct { + u64 lt_slp_entry_error_sts : 1; + u64 lt_secrets_sts : 1; + u64 lt_block_mem_sts : 1; + u64 lt_reset_sts : 1; + }; +} lt_e2sts_t; + +/* + * format of LT.STS register + */ +typedef union { + u64 _raw; + struct { + u64 senter_done_sts : 1; + u64 sexit_done_sts : 1; + u64 reserved1 : 2; + u64 lt_mem_unlock_sts : 1; + u64 lt_nodma_en_sts : 1; + u64 lt_mem_config_lock_sts : 1; + u64 lt_private_open_sts : 1; + u64 reserved2 : 1; + u64 lt_nodma_cache_sts : 1; + u64 lt_nodma_table_prot_sts : 1; + u64 lt_mem_config_ok_sts : 1; + }; +} lt_sts_t; + + +/* + * fns to read/write LT config regs + */ + +/* returns proper addr (virt from fixmap or phys) depending on proc mode */ +extern u32 config_reg_base_addr(u32 base_phys); + +static inline u64 read_config_reg(u32 config_regs_base, u32 reg) +{ + /* these are MMIO so make sure compiler doesn't optimize */ + return *(volatile u64 *)(config_reg_base_addr(config_regs_base) + reg); +} + +static inline void write_config_reg(u32 config_regs_base, u32 reg, u64 val) +{ + /* these are MMIO so make sure compiler doesn't optimize */ + *(volatile u64 *)(config_reg_base_addr(config_regs_base) + reg) = val; +} + +static inline u64 read_pub_config_reg(u32 reg) +{ + return read_config_reg(LT_PUB_CONFIG_REGS_BASE, reg); +} + +static inline void write_pub_config_reg(u32 reg, u64 val) +{ + write_config_reg(LT_PUB_CONFIG_REGS_BASE, reg, val); +} + +static inline u64 read_priv_config_reg(u32 reg) +{ + return read_config_reg(LT_PRIV_CONFIG_REGS_BASE, reg); +} + +static inline void write_priv_config_reg(u32 reg, u64 val) +{ + write_config_reg(LT_PRIV_CONFIG_REGS_BASE, reg, val); +} + +/* this is a common use with annoying casting, so make it an inline */ +static inline lt_heap_t *get_lt_heap(void) +{ + return (lt_heap_t *)(unsigned long)read_pub_config_reg(LTCR_LT_HEAP_BASE); +} + +#endif /* __ASM_X86_SMX_CONFIG_REGS_H__ */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r 765b7e23d979 -r 843be4e340c8 xen/include/asm-x86/smx/mtrrs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/include/asm-x86/smx/mtrrs.h Fri Sep 01 18:28:21 2006 +0800 @@ -0,0 +1,124 @@ +/* + * mtrrs.c: LT MTRR-related definitions + * + * Copyright (c) 2003-2006, 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 __ASM_X86_SMX_MTRRS_H__ +#define __ASM_X86_SMX_MTRRS_H__ + +#include + +enum var_mtrr_t { + MTRR_PHYS_BASE0_MSR = 0x200, + MTRR_PHYS_MASK0_MSR = 0x201, + MTRR_PHYS_BASE1_MSR = 0x202, + MTRR_PHYS_MASK1_MSR = 0x203, + MTRR_PHYS_BASE2_MSR = 0x204, + MTRR_PHYS_MASK2_MSR = 0x205, + MTRR_PHYS_BASE3_MSR = 0x206, + MTRR_PHYS_MASK3_MSR = 0x207, + MTRR_PHYS_BASE4_MSR = 0x208, + MTRR_PHYS_MASK4_MSR = 0x209, + MTRR_PHYS_BASE5_MSR = 0x20A, + MTRR_PHYS_MASK5_MSR = 0x20B, + MTRR_PHYS_BASE6_MSR = 0x20C, + MTRR_PHYS_MASK6_MSR = 0x20D, + MTRR_PHYS_BASE7_MSR = 0x20E, + MTRR_PHYS_MASK7_MSR = 0x20F +}; + +typedef union { + u64 raw; + struct { + u64 vcnt : 8; /* num variable MTRR pairs */ + u64 fix : 1; /* fixed range MTRRs are supported */ + u64 reserved1 : 1; + u64 wc : 1; /* write-combining mem type supported */ + u64 reserved2 : 53; + }; +} mtrr_cap_t; + +typedef union { + u64 raw; + struct { + u64 type : 8; + u64 reserved1 : 2; + u64 fe : 1; /* fixed MTRR enable */ + u64 e : 1; /* (all) MTRR enable */ + u64 reserved2 : 52; + }; +} mtrr_def_type_t; + +typedef union { + u64 raw; + struct { + u64 type : 8; + u64 reserved1 : 4; + u64 base : 24; + u64 reserved2 : 28; + }; +} mtrr_physbase_t; + +typedef union { + u64 raw; + struct { + u64 reserved1 : 11; + u64 v : 1; /* valid */ + u64 mask : 24; + u64 reserved2 : 28; + }; +} mtrr_physmask_t; + +/* current procs only have 8, so this should hold us for a while */ +#define MAX_VARIABLE_MTRRS 16 + +typedef struct { + mtrr_def_type_t mtrr_def_type; + int num_var_mtrrs; + mtrr_physbase_t mtrr_physbases[MAX_VARIABLE_MTRRS]; + mtrr_physmask_t mtrr_physmasks[MAX_VARIABLE_MTRRS]; +} mtrr_state_t; + + +#endif /*__ASM_X86_SMX_MTRRS_H__ */ + + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r 765b7e23d979 -r 843be4e340c8 xen/include/asm-x86/smx/smx.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/include/asm-x86/smx/smx.h Fri Sep 01 18:28:21 2006 +0800 @@ -0,0 +1,363 @@ +/* + * smx.h: LT SMX architecture-related definitions + * + * Copyright (c) 2003-2006, 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 __ASM_X86_SMX_SMX_H__ +#define __ASM_X86_SMX_SMX_H__ + +#include +#include +#include +#include +#include + +/* + * LT device space + */ + +#define TPM_LOCALITY_BASE 0xfed40000 +#define NR_TPM_LOCALITY_PAGES ((TPM_LOCALITY_1 - TPM_LOCALITY_0) >> \ + PAGE_SHIFT) + +#define TPM_LOCALITY_0 TPM_LOCALITY_BASE +#define TPM_LOCALITY_1 (TPM_LOCALITY_BASE | 0x1000) +#define TPM_LOCALITY_2 (TPM_LOCALITY_BASE | 0x2000) +/* these localities (3+4) are mostly not usable by Xen */ +#define TPM_LOCALITY_3 (TPM_LOCALITY_BASE | 0x3000) +#define TPM_LOCALITY_4 (TPM_LOCALITY_BASE | 0x4000) + +#define TPM_LOCALITY_BASE_N(n) (TPM_LOCALITY_BASE | ((n) << 12)) + + +/* + * data-passing structures contained in LT heap: + * - BIOS to OS/loader + * - OS/loader to MVMM + * - OS/loader to SINIT + * - SINIT to MVMM + */ + +/* + * BIOS to OS/loader structure + * - not used by current Xen + */ +typedef struct { + u32 version; /* will be 0x00 */ + u32 bios_sinit_size; +} bios_os_data_v0_t; + +/* + * OS/loader to MVMM structure v1 + * - private to Xen (so can be any format we need) + */ +typedef struct { + u32 version; /* will be 0x01 */ + mtrr_state_t saved_mtrr_state; /* saved prior to changes for SINIT */ + multiboot_info_t *mbi; /* needs to be restored to ebx */ +} os_mvmm_data_v1_t; + +/* + * OS/loader to SINIT structure v1 + */ +typedef struct { + u32 version; /* will be 0x01 */ + u32 reserved; + u32 mvmm_ptab_lo; + u32 mvmm_ptab_hi; + u32 mvmm_size_lo; + u32 mvmm_size_hi; + u32 mvmm_hdr_base_lo; + u32 mvmm_hdr_base_hi; +} os_sinit_data_v1_t; + +/* + * SINIT to MVMM structure v1 + */ +#define MDR_MEMTYPE_GOOD 0x00 +#define MDR_MEMTYPE_SMM_OVERLAY 0x01 +#define MDR_MEMTYPE_SMM_NONOVERLAY 0x02 +#define MDR_MEMTYPE_PCIE_CONFIG_SPACE 0x03 +#define MDR_MEMTYPE_PROTECTED 0x04 + +typedef struct __attribute__ ((packed)) { + u32 start_lo; + u32 start_hi; + u32 length_lo; + u32 length_hi; + u8 mem_type; + u8 reserved[7]; +} sinit_mdr_t; + +typedef struct { + u32 version; /* will be 0x01 */ + u32 num_mdrs; + sinit_mdr_t mdrs[]; +} sinit_mvmm_data_v1_t; + + +/* + * LT heap data format and field accessor fns + */ + +/* + * offset length field + * ------ ------ ----- + * 0 8 bios_os_data_size + * 8 bios_os_data_size - 8 bios_os_data + * + * bios_os_data_size 8 os_mvmm_data_size + * bios_os_data_size + os_mvmm_data_size - 8 os_mvmm_data + * 8 + * + * bios_os_data_size + 8 os_sinit_data_size + * os_mvmm_data_size + * bios_os_data_size + os_sinit_data_size - 8 os_sinit_data + * os_mvmm_data_size + + * 8 + * + * bios_os_data_size + 8 sinit_mvmm_data_size + * os_mvmm_data_size + + * os_sinit_data_size + * bios_os_data_size + sinit_mvmm_data_size - 8 sinit_mvmm_data + * os_mvmm_data_size + + * os_sinit_data_size + + * 8 + */ + +typedef void lt_heap_t; + +typedef struct { + u32 version; +} lt_heap_data_hdr_t; + +static inline u64 *get_data_size_addr(void *data_start) +{ + return (u64 *)(data_start - sizeof(u64)); +} + +static inline u64 get_bios_os_data_size(lt_heap_t *lt_heap) +{ + return *(u64 *)lt_heap; +} + +static inline lt_heap_data_hdr_t *get_bios_os_data_start(lt_heap_t *lt_heap) +{ + return (lt_heap_data_hdr_t *)((char*)lt_heap + sizeof(u64)); +} + +static inline u64 get_os_mvmm_data_size(lt_heap_t *lt_heap) +{ + return *(u64 *)(lt_heap + get_bios_os_data_size(lt_heap)); +} + +static inline lt_heap_data_hdr_t *get_os_mvmm_data_start(lt_heap_t *lt_heap) +{ + return (lt_heap_data_hdr_t *)(lt_heap + get_bios_os_data_size(lt_heap) + + sizeof(u64)); +} + +static inline u64 get_os_sinit_data_size(lt_heap_t *lt_heap) +{ + return *(u64 *)(lt_heap + get_bios_os_data_size(lt_heap) + + get_os_mvmm_data_size(lt_heap)); +} + +static inline lt_heap_data_hdr_t *get_os_sinit_data_start(lt_heap_t *lt_heap) +{ + return (lt_heap_data_hdr_t *)(lt_heap + get_bios_os_data_size(lt_heap) + + get_os_mvmm_data_size(lt_heap) + + sizeof(u64)); +} + +static inline u64 get_sinit_mvmm_data_size(lt_heap_t *lt_heap) +{ + return *(u64 *)(lt_heap + get_bios_os_data_size(lt_heap) + + get_os_mvmm_data_size(lt_heap) + + get_os_sinit_data_size(lt_heap)); +} + +static inline lt_heap_data_hdr_t *get_sinit_mvmm_data_start(lt_heap_t *lt_heap) +{ + return (lt_heap_data_hdr_t *)(lt_heap + get_bios_os_data_size(lt_heap) + + get_os_mvmm_data_size(lt_heap) + + get_os_sinit_data_size(lt_heap) + + sizeof(u64)); +} + + +/* + * MVMM header structure + * describes an MVMM for SINIT and OS/loader SW + */ +typedef struct { + u32 guid[4]; + u32 length; + u32 version; + u32 entry_point; + u32 req_mem_size; + u32 features; +} mvmm_hdr_t; + + +/* + * RLP JOIN structure for GETSEC[WAKEUP] + */ +typedef struct { + u32 gdt_limit; + u32 gdt_base; + u32 seg_sel; /* cs (ds, es, ss are seg_sel+8) */ + u32 entry_point; /* phys addr */ +} mvmm_join_t; + +/* + * GETSEC[] instructions + */ + +/* GETSEC instruction opcode */ +#define IA32_GETSEC_OPCODE ".byte 0x0f,0x37" + +/* GETSEC leaf function codes */ +#define IA32_GETSEC_CAPABILITIES 0 +#define IA32_GETSEC_SENTER 4 +#define IA32_GETSEC_SEXIT 5 +#define IA32_GETSEC_PARAMETERS 6 +#define IA32_GETSEC_SMCTRL 7 +#define IA32_GETSEC_WAKEUP 8 + +/* + * GETSEC[] leaf functions + */ + +typedef union { + u32 _raw; + struct { + u32 chipset_present : 1; + u32 undefined1 : 1; + u32 enteraccs : 1; + u32 exitac : 1; + u32 senter : 1; + u32 sexit : 1; + u32 parameters : 1; + u32 smctrl : 1; + u32 wakeup : 1; + u32 undefined9 : 22; + u32 extended_leafs : 1; + }; +} capabilities_t; + +static inline capabilities_t __getsec_capabilities(u32 index) +{ + u32 cap; + __asm__ __volatile__ (IA32_GETSEC_OPCODE "\n" + : "=a"(cap) + : "a"(IA32_GETSEC_CAPABILITIES), "b"(index)); + return (capabilities_t)cap; +} + +static inline void __getsec_senter(u32 sinit_base, u32 sinit_size) +{ + __asm__ __volatile__ (IA32_GETSEC_OPCODE "\n" + : + : "a"(IA32_GETSEC_SENTER), + "b"(sinit_base), + "c"(sinit_size), + "d"(0x0)); +} + +static inline void __getsec_sexit(void) +{ + __asm__ __volatile__ (IA32_GETSEC_OPCODE "\n" + : : "a"(IA32_GETSEC_SEXIT)); +} + +static inline void __getsec_wakeup(void) +{ + __asm__ __volatile__ (IA32_GETSEC_OPCODE "\n" + : : "a"(IA32_GETSEC_WAKEUP)); +} + +static inline void __getsec_smctrl(void) +{ + __asm__ __volatile__ (IA32_GETSEC_OPCODE "\n" + : : "a"(IA32_GETSEC_SMCTRL), "b"(0x0)); +} + +static inline void __getsec_parameters(u32 index, int* param_type, + u32* peax, u32* pebx, u32* pecx) +{ + u32 eax=0, ebx=0, ecx=0; + __asm__ __volatile__ (IA32_GETSEC_OPCODE "\n" + : "=a"(eax), "=b"(ebx), "=c"(ecx) + : "a"(IA32_GETSEC_PARAMETERS), "b"(index)); + + if ( param_type != NULL ) *param_type = eax & 0x1f; + if ( peax != NULL ) *peax = eax; + if ( pebx != NULL ) *pebx = ebx; + if ( pecx != NULL ) *pecx = ecx; +} + + +/* used for debugging in very early boot environment */ +void early_serial_printk(const char *fmt, ...); + +/* used in shutdown.c */ +extern void smx_scrub_proc(void); +extern void smx_scrub_mem(void); +extern void smx_teardown(void); + +/* manage MTRRs for launch of AC module (SINIT) */ +void save_mtrrs(mtrr_state_t *saved_state); +void restore_mtrrs(mtrr_state_t *saved_state); +int set_mem_type(void *base, u32 size, u32 mem_type); +void set_all_mtrrs(bool enable); + +int smx_reserve_memory(struct e820map *map); + +bool smx_in_prot_env(void); + +void display_errors(void); + +int verify_tpm_ready(void); + +#endif /* __ASM_X86_SMX_SMX_H__ */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */