+} + +static inline void write_priv_config_reg(uint32_t reg, uint64_t val) +{ + write_config_reg(TXT_PRIV_CONFIG_REGS_BASE, reg, val); +} + +#endif /* __TXT_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 419625d61514 -r de5826b5b302 sboot/include/txt/errorcode.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sboot/include/txt/errorcode.h Fri Jun 08 16:57:19 2007 -0700 @@ -0,0 +1,91 @@ +/* + * errorcode.h: Intel(r) TXT error definitions for ERRORCODE config register + * + * Copyright (c) 2003-2007, 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 __TXT_ERRORCODE_H__ +#define __TXT_ERRORCODE_H__ + +/* + * error values for processor error codes (ERRORCODE.external = 0) + */ +#define TXT_ERR_PROC_LEGACY_SHUTDOWN 0 +#define TXT_ERR_PROC_INVALID_ACM_MEM_TYPE 5 +#define TXT_ERR_PROC_UNSUPPORTED_ACM 6 +#define TXT_ERR_PROC_AUTH_FAIL 7 +#define TXT_ERR_PROC_INVALID_ACM_FORMAT 8 +#define TXT_ERR_PROC_UNEXPECTED_HITM 9 +#define TXT_ERR_PROC_INVALID_EVENT 10 +#define TXT_ERR_PROC_INVALID_JOIN_FORMAT 11 +#define TXT_ERR_PROC_UNRECOVERABLE_MCE 12 +#define TXT_ERR_PROC_VMX_ABORT 13 +#define TXT_ERR_PROC_ACM_CORRUPT 14 +#define TXT_ERR_PROC_INVALID_VIDB_RATIO 15 + +/* + * for SW errors (ERRORCODE.external = 1) + */ +typedef union { + uint16_t _raw; + struct { + uint16_t err : 15; /* specific to src */ + uint16_t src : 1; /* 0=ACM, 1=other */ + }; +} txt_errorcode_sw_t; + +/* + * ACM errors (txt_errorcode_sw_t.src=0), format of err field + */ +typedef union { + uint16_t _raw; + struct { + uint16_t type : 4; /* 0000=BIOS ACM, 0001=SINIT, */ + /* 0010-1111=reserved */ + uint16_t progress : 6; + uint16_t error : 4; + uint16_t reserved : 1; + }; +} acmod_error_t; + +#endif /* __TXT_ERRORCODE_H__ */ + + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r 419625d61514 -r de5826b5b302 sboot/include/txt/heap.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sboot/include/txt/heap.h Fri Jun 08 16:57:19 2007 -0700 @@ -0,0 +1,209 @@ +/* + * heap.h: Intel(r) TXT heap definitions + * + * Copyright (c) 2003-2007, 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 __TXT_HEAP_H__ +#define __TXT_HEAP_H__ + +#include +#include +#include +#include + +/* + * data-passing structures contained in TXT heap: + * - BIOS to OS/loader + * - OS/loader to MLE + * - OS/loader to SINIT + * - SINIT to MLE + */ + +/* + * BIOS to OS/loader structure + * - not used by current Xen + */ +typedef struct { + uint32_t version; /* SDP3/TEP=0x00 */ + uint32_t bios_sinit_size; +} bios_os_data_t; + +/* + * OS/loader to MLE structure v1 + * - private to Xen (so can be any format we need) + */ +typedef struct { + uint32_t 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_mle_data_t; + +/* + * OS/loader to SINIT structure v1 + */ +typedef struct { + uint32_t version; /* SDP3/TEP=0x01 */ + uint32_t reserved; + uint64_t mle_ptab; + uint64_t mle_size; + uint64_t mle_hdr_base; +} os_sinit_data_t; + +/* + * SINIT to MLE structure + */ +#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)) { + uint64_t base; + uint64_t length; + uint8_t mem_type; + uint8_t reserved[7]; +} sinit_mdr_t; + +#define SHA1_SIZE 20 +typedef uint8_t sha1_hash_t[SHA1_SIZE]; + +typedef struct { + uint32_t version; /* SDP3/TEP=0x01 */ + union { + struct { + uint32_t num_mdrs; + sinit_mdr_t mdrs[]; + } v1; + }; +} sinit_mle_data_t; + + +/* + * TXT 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_mle_data_size + * bios_os_data_size + os_mle_data_size - 8 os_mle_data + * 8 + * + * bios_os_data_size + 8 os_sinit_data_size + * os_mle_data_size + * bios_os_data_size + os_sinit_data_size - 8 os_sinit_data + * os_mle_data_size + + * 8 + * + * bios_os_data_size + 8 sinit_mle_data_size + * os_mle_data_size + + * os_sinit_data_size + * bios_os_data_size + sinit_mle_data_size - 8 sinit_mle_data + * os_mle_data_size + + * os_sinit_data_size + + * 8 + */ + +typedef void txt_heap_t; + +/* this is a common use with annoying casting, so make it an inline */ +static inline txt_heap_t *get_txt_heap(void) +{ + return (txt_heap_t *)(unsigned long)read_pub_config_reg(TXTCR_HEAP_BASE); +} + +static inline uint64_t get_bios_os_data_size(txt_heap_t *heap) +{ + return *(uint64_t *)heap; +} + +static inline bios_os_data_t *get_bios_os_data_start(txt_heap_t *heap) +{ + return (bios_os_data_t *)((char*)heap + sizeof(uint64_t)); +} + +static inline uint64_t get_os_mle_data_size(txt_heap_t *heap) +{ + return *(uint64_t *)(heap + get_bios_os_data_size(heap)); +} + +static inline os_mle_data_t *get_os_mle_data_start(txt_heap_t *heap) +{ + return (os_mle_data_t *)(heap + get_bios_os_data_size(heap) + + sizeof(uint64_t)); +} + +static inline uint64_t get_os_sinit_data_size(txt_heap_t *heap) +{ + return *(uint64_t *)(heap + get_bios_os_data_size(heap) + + get_os_mle_data_size(heap)); +} + +static inline os_sinit_data_t *get_os_sinit_data_start(txt_heap_t *heap) +{ + return (os_sinit_data_t *)(heap + get_bios_os_data_size(heap) + + get_os_mle_data_size(heap) + + sizeof(uint64_t)); +} + +static inline uint64_t get_sinit_mle_data_size(txt_heap_t *heap) +{ + return *(uint64_t *)(heap + get_bios_os_data_size(heap) + + get_os_mle_data_size(heap) + + get_os_sinit_data_size(heap)); +} + +static inline sinit_mle_data_t *get_sinit_mle_data_start(txt_heap_t *heap) +{ + return (sinit_mle_data_t *)(heap + get_bios_os_data_size(heap) + + get_os_mle_data_size(heap) + + get_os_sinit_data_size(heap) + + sizeof(uint64_t)); +} + +#endif /* __TXT_HEAP_H__ */ + + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r 419625d61514 -r de5826b5b302 sboot/include/txt/mtrrs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sboot/include/txt/mtrrs.h Fri Jun 08 16:57:19 2007 -0700 @@ -0,0 +1,129 @@ +/* + * mtrrs.c: Intel(r) TXT MTRR-related definitions + * + * Copyright (c) 2003-2007, 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 __TXT_MTRRS_H__ +#define __TXT_MTRRS_H__ + +#include +#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 { + uint64_t raw; + struct { + uint64_t vcnt : 8; /* num variable MTRR pairs */ + uint64_t fix : 1; /* fixed range MTRRs are supported */ + uint64_t reserved1 : 1; + uint64_t wc : 1; /* write-combining mem type supported */ + uint64_t reserved2 : 53; + }; +} mtrr_cap_t; + +typedef union { + uint64_t raw; + struct { + uint64_t type : 8; + uint64_t reserved1 : 2; + uint64_t fe : 1; /* fixed MTRR enable */ + uint64_t e : 1; /* (all) MTRR enable */ + uint64_t reserved2 : 52; + }; +} mtrr_def_type_t; + +typedef union { + uint64_t raw; + struct { + uint64_t type : 8; + uint64_t reserved1 : 4; + uint64_t base : 24; + uint64_t reserved2 : 28; + }; +} mtrr_physbase_t; + +typedef union { + uint64_t raw; + struct { + uint64_t reserved1 : 11; + uint64_t v : 1; /* valid */ + uint64_t mask : 24; + uint64_t 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; + +extern void save_mtrrs(mtrr_state_t *saved_state); +extern void set_all_mtrrs(bool enable); +extern bool set_mem_type(void *base, uint32_t size, uint32_t mem_type); +extern void restore_mtrrs(mtrr_state_t *saved_state); + +#endif /*__TXT_MTRRS_H__ */ + + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r 419625d61514 -r de5826b5b302 sboot/include/txt/smx.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sboot/include/txt/smx.h Fri Jun 08 16:57:19 2007 -0700 @@ -0,0 +1,138 @@ +/* + * smx.h: Intel(r) TXT SMX architecture-related definitions + * + * Copyright (c) 2003-2007, 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 __TXT_SMX_H__ +#define __TXT_SMX_H__ + +/* + * 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 { + uint32_t _raw; + struct { + uint32_t chipset_present : 1; + uint32_t undefined1 : 1; + uint32_t enteraccs : 1; + uint32_t exitac : 1; + uint32_t senter : 1; + uint32_t sexit : 1; + uint32_t parameters : 1; + uint32_t smctrl : 1; + uint32_t wakeup : 1; + uint32_t undefined9 : 22; + uint32_t extended_leafs : 1; + }; +} capabilities_t; + +static inline capabilities_t __getsec_capabilities(uint32_t index) +{ + uint32_t cap; + __asm__ __volatile__ (IA32_GETSEC_OPCODE "\n" + : "=a"(cap) + : "a"(IA32_GETSEC_CAPABILITIES), "b"(index)); + return (capabilities_t)cap; +} + +static inline void __getsec_senter(uint32_t sinit_base, uint32_t 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(uint32_t index, int* param_type, + uint32_t* peax, uint32_t* pebx, + uint32_t* pecx) +{ + uint32_t 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; +} + + +#endif /* __TXT_SMX_H__ */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r 419625d61514 -r de5826b5b302 sboot/include/txt/txt.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sboot/include/txt/txt.h Fri Jun 08 16:57:19 2007 -0700 @@ -0,0 +1,90 @@ +/* + * txt.h: Intel(r) TXT general definitions and support functions + * + * Copyright (c) 2003-2007, 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 __TXT_TXT_H__ +#define __TXT_TXT_H__ + +#include + +/* + * MLE header structure + * describes an MLE for SINIT and OS/loader SW + */ +typedef struct { + uint32_t guid[4]; + uint32_t length; + uint32_t version; + uint32_t entry_point; + uint32_t req_mem_size; + uint32_t features; +} mle_hdr_t; + + +/* + * RLP JOIN structure for GETSEC[WAKEUP] + */ +typedef struct { + uint32_t gdt_limit; + uint32_t gdt_base; + uint32_t seg_sel; /* cs (ds, es, ss are seg_sel+8) */ + uint32_t entry_point; /* phys addr */ +} mle_join_t; + +extern bool txt_is_launched(void); +extern bool txt_get_error(void); +extern bool txt_verify_platform(void); +extern bool txt_prepare_cpu(void); +extern bool txt_prepare_platform(void); +extern bool txt_launch_environment(multiboot_info_t *mbi); +extern bool txt_post_launch(void); +extern bool txt_protect_mem_regions(void); +extern bool txt_post_launch_verify_platform(void); + +/* in common/sboot.c */ +extern void cpu_wakeup(uint32_t cpuid); + + +#endif /* __TXT_TXT_H__ */ + + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r 419625d61514 -r de5826b5b302 sboot/include/txt/verify.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sboot/include/txt/verify.h Fri Jun 08 16:57:19 2007 -0700 @@ -0,0 +1,53 @@ +/* + * verify.h: support functions for platform Intel(r) TXT verification + * + * Copyright (c) 2003-2007, 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 __TXT_VERIFY_H__ +#define __TXT_VERIFY_H__ + +extern bool verify_txt_heap(txt_heap_t *txt_heap, bool bios_os_data_only); +extern void print_os_sinit_data(os_sinit_data_t *os_sinit_data); + +#endif /* __TXT_VERIFY_H__ */ + + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r 419625d61514 -r de5826b5b302 sboot/include/txt/vmcs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sboot/include/txt/vmcs.h Fri Jun 08 16:57:19 2007 -0700 @@ -0,0 +1,327 @@ +#ifndef __TXT_VMCS_H__ +#define __TXT_VMCS_H__ + +struct vmcs_struct { + uint32_t vmcs_revision_id; + unsigned char data[0]; /* vmcs size is read from MSR */ +}; + +union vmcs_arbytes { + struct arbyte_fields { + unsigned int seg_type : 4, + s : 1, + dpl : 2, + p : 1, + reserved0 : 4, + avl : 1, + reserved1 : 1, + default_ops_size: 1, + g : 1, + null_bit : 1, + reserved2 : 15; + } fields; + unsigned int bytes; +}; + +#define CPU_BASED_HLT_EXITING 0x00000080 +#define CPU_BASED_INVDPG_EXITING 0x00000200 +#define CPU_BASED_MWAIT_EXITING 0x00000400 + +#define PIN_BASED_EXT_INTR_MASK 0x00000001 +#define PIN_BASED_NMI_EXITING 0x00000008 + +#define VM_EXIT_IA32E_MODE 0x00000200 +#define VM_EXIT_ACK_INTR_ON_EXIT 0x00008000 + +#define VM_ENTRY_IA32E_MODE 0x00000200 +#define VM_ENTRY_SMM 0x00000400 +#define VM_ENTRY_DEACT_DUAL_MONITOR 0x00000800 + + +/* VMCS Encordings */ +enum vmcs_field { + GUEST_ES_SELECTOR = 0x00000800, + GUEST_CS_SELECTOR = 0x00000802, + GUEST_SS_SELECTOR = 0x00000804, + GUEST_DS_SELECTOR = 0x00000806, + GUEST_FS_SELECTOR = 0x00000808, + GUEST_GS_SELECTOR = 0x0000080a, + GUEST_LDTR_SELECTOR = 0x0000080c, + GUEST_TR_SELECTOR = 0x0000080e, + HOST_ES_SELECTOR = 0x00000c00, + HOST_CS_SELECTOR = 0x00000c02, + HOST_SS_SELECTOR = 0x00000c04, + HOST_DS_SELECTOR = 0x00000c06, + HOST_FS_SELECTOR = 0x00000c08, + HOST_GS_SELECTOR = 0x00000c0a, + HOST_TR_SELECTOR = 0x00000c0c, + IO_BITMAP_A = 0x00002000, + IO_BITMAP_A_HIGH = 0x00002001, + IO_BITMAP_B = 0x00002002, + IO_BITMAP_B_HIGH = 0x00002003, + VM_EXIT_MSR_STORE_ADDR = 0x00002006, + VM_EXIT_MSR_STORE_ADDR_HIGH = 0x00002007, + VM_EXIT_MSR_LOAD_ADDR = 0x00002008, + VM_EXIT_MSR_LOAD_ADDR_HIGH = 0x00002009, + VM_ENTRY_MSR_LOAD_ADDR = 0x0000200a, + VM_ENTRY_MSR_LOAD_ADDR_HIGH = 0x0000200b, + TSC_OFFSET = 0x00002010, + TSC_OFFSET_HIGH = 0x00002011, + VIRTUAL_APIC_PAGE_ADDR = 0x00002012, + VIRTUAL_APIC_PAGE_ADDR_HIGH = 0x00002013, + VMCS_LINK_POINTER = 0x00002800, + VMCS_LINK_POINTER_HIGH = 0x00002801, + GUEST_IA32_DEBUGCTL = 0x00002802, + GUEST_IA32_DEBUGCTL_HIGH = 0x00002803, + PIN_BASED_VM_EXEC_CONTROL = 0x00004000, + CPU_BASED_VM_EXEC_CONTROL = 0x00004002, + EXCEPTION_BITMAP = 0x00004004, + PAGE_FAULT_ERROR_CODE_MASK = 0x00004006, + PAGE_FAULT_ERROR_CODE_MATCH = 0x00004008, + CR3_TARGET_COUNT = 0x0000400a, + VM_EXIT_CONTROLS = 0x0000400c, + VM_EXIT_MSR_STORE_COUNT = 0x0000400e, + VM_EXIT_MSR_LOAD_COUNT = 0x00004010, + VM_ENTRY_CONTROLS = 0x00004012, + VM_ENTRY_MSR_LOAD_COUNT = 0x00004014, + VM_ENTRY_INTR_INFO_FIELD = 0x00004016, + VM_ENTRY_EXCEPTION_ERROR_CODE = 0x00004018, + VM_ENTRY_INSTRUCTION_LEN = 0x0000401a, + TPR_THRESHOLD = 0x0000401c, + SECONDARY_VM_EXEC_CONTROL = 0x0000401e, + VM_INSTRUCTION_ERROR = 0x00004400, + VM_EXIT_REASON = 0x00004402, + VM_EXIT_INTR_INFO = 0x00004404, + VM_EXIT_INTR_ERROR_CODE = 0x00004406, + IDT_VECTORING_INFO_FIELD = 0x00004408, + IDT_VECTORING_ERROR_CODE = 0x0000440a, + VM_EXIT_INSTRUCTION_LEN = 0x0000440c, + VMX_INSTRUCTION_INFO = 0x0000440e, + GUEST_ES_LIMIT = 0x00004800, + GUEST_CS_LIMIT = 0x00004802, + GUEST_SS_LIMIT = 0x00004804, + GUEST_DS_LIMIT = 0x00004806, + GUEST_FS_LIMIT = 0x00004808, + GUEST_GS_LIMIT = 0x0000480a, + GUEST_LDTR_LIMIT = 0x0000480c, + GUEST_TR_LIMIT = 0x0000480e, + GUEST_GDTR_LIMIT = 0x00004810, + GUEST_IDTR_LIMIT = 0x00004812, + GUEST_ES_AR_BYTES = 0x00004814, + GUEST_CS_AR_BYTES = 0x00004816, + GUEST_SS_AR_BYTES = 0x00004818, + GUEST_DS_AR_BYTES = 0x0000481a, + GUEST_FS_AR_BYTES = 0x0000481c, + GUEST_GS_AR_BYTES = 0x0000481e, + GUEST_LDTR_AR_BYTES = 0x00004820, + GUEST_TR_AR_BYTES = 0x00004822, + GUEST_INTERRUPTIBILITY_INFO = 0x00004824, + GUEST_ACTIVITY_STATE = 0x00004826, + GUEST_SYSENTER_CS = 0x0000482A, + HOST_IA32_SYSENTER_CS = 0x00004c00, + CR0_GUEST_HOST_MASK = 0x00006000, + CR4_GUEST_HOST_MASK = 0x00006002, + CR0_READ_SHADOW = 0x00006004, + CR4_READ_SHADOW = 0x00006006, + CR3_TARGET_VALUE0 = 0x00006008, + CR3_TARGET_VALUE1 = 0x0000600a, + CR3_TARGET_VALUE2 = 0x0000600c, + CR3_TARGET_VALUE3 = 0x0000600e, + EXIT_QUALIFICATION = 0x00006400, + GUEST_LINEAR_ADDRESS = 0x0000640a, + GUEST_CR0 = 0x00006800, + GUEST_CR3 = 0x00006802, + GUEST_CR4 = 0x00006804, + GUEST_ES_BASE = 0x00006806, + GUEST_CS_BASE = 0x00006808, + GUEST_SS_BASE = 0x0000680a, + GUEST_DS_BASE = 0x0000680c, + GUEST_FS_BASE = 0x0000680e, + GUEST_GS_BASE = 0x00006810, + GUEST_LDTR_BASE = 0x00006812, + GUEST_TR_BASE = 0x00006814, + GUEST_GDTR_BASE = 0x00006816, + GUEST_IDTR_BASE = 0x00006818, + GUEST_DR7 = 0x0000681a, + GUEST_RSP = 0x0000681c, + GUEST_RIP = 0x0000681e, + GUEST_RFLAGS = 0x00006820, + GUEST_PENDING_DBG_EXCEPTIONS = 0x00006822, + GUEST_SYSENTER_ESP = 0x00006824, + GUEST_SYSENTER_EIP = 0x00006826, + HOST_CR0 = 0x00006c00, + HOST_CR3 = 0x00006c02, + HOST_CR4 = 0x00006c04, + HOST_FS_BASE = 0x00006c06, + HOST_GS_BASE = 0x00006c08, + HOST_TR_BASE = 0x00006c0a, + HOST_GDTR_BASE = 0x00006c0c, + HOST_IDTR_BASE = 0x00006c0e, + HOST_IA32_SYSENTER_ESP = 0x00006c10, + HOST_IA32_SYSENTER_EIP = 0x00006c12, + HOST_RSP = 0x00006c14, + HOST_RIP = 0x00006c16, +}; + +/* VMX stuff */ +enum ap_init_state { + AP_WAIT_INIT = 0, + AP_WAIT_SIPI1 = 1, + AP_WAIT_SIPI2 = 2, + AP_WAIT_DONE = 3, +}; + +enum guest_activity_state { + GUEST_STATE_ACTIVE = 0, + GUEST_STATE_HALT = 1, + GUEST_STATE_SHUTDOWN = 2, + GUEST_STATE_WAIT_SIPI = 3, +}; + +#define VMCALL_OPCODE ".byte 0x0f,0x01,0xc1\n" +#define VMCLEAR_OPCODE ".byte 0x66,0x0f,0xc7\n" /* reg/opcode: /6 */ +#define VMLAUNCH_OPCODE ".byte 0x0f,0x01,0xc2\n" +#define VMPTRLD_OPCODE ".byte 0x0f,0xc7\n" /* reg/opcode: /6 */ +#define VMPTRST_OPCODE ".byte 0x0f,0xc7\n" /* reg/opcode: /7 */ +#define VMREAD_OPCODE ".byte 0x0f,0x78\n" +#define VMRESUME_OPCODE ".byte 0x0f,0x01,0xc3\n" +#define VMWRITE_OPCODE ".byte 0x0f,0x79\n" +#define VMXOFF_OPCODE ".byte 0x0f,0x01,0xc4\n" +#define VMXON_OPCODE ".byte 0xf3,0x0f,0xc7\n" + +#define MODRM_EAX_06 ".byte 0x30\n" /* [EAX], with reg/opcode: /6 */ +#define MODRM_EAX_07 ".byte 0x38\n" /* [EAX], with reg/opcode: /7 */ +#define MODRM_EAX_ECX ".byte 0xc1\n" /* [EAX], [ECX] */ + +/* + * Exit Reasons + */ +#define VMX_EXIT_REASONS_FAILED_VMENTRY 0x80000000 + +#define EXIT_REASON_INIT 3 +#define EXIT_REASON_SIPI 4 + +#define EXIT_REASON_INVALID_GUEST_STATE 33 +#define EXIT_REASON_MSR_LOADING 34 + +#define EXIT_REASON_MACHINE_CHECK 41 + +static inline void __vmptrld(uint64_t addr) +{ + __asm__ __volatile__ ( VMPTRLD_OPCODE + MODRM_EAX_06 + /* CF==1 or ZF==1 --> crash (ud2) */ + "ja 1f ; ud2 ; 1:\n" + : + : "a" (&addr) + : "memory"); +} + +static inline void __vmptrst(uint64_t addr) +{ + __asm__ __volatile__ ( VMPTRST_OPCODE + MODRM_EAX_07 + : + : "a" (&addr) + : "memory"); +} + +static inline void __vmpclear(uint64_t addr) +{ + __asm__ __volatile__ ( VMCLEAR_OPCODE + MODRM_EAX_06 + /* CF==1 or ZF==1 --> crash (ud2) */ + "ja 1f ; ud2 ; 1:\n" + : + : "a" (&addr) + : "memory"); +} + +static inline unsigned long __vmread(unsigned long field) +{ + unsigned long ecx; + + __asm__ __volatile__ ( VMREAD_OPCODE + MODRM_EAX_ECX + /* CF==1 or ZF==1 --> crash (ud2) */ + "ja 1f ; ud2 ; 1:\n" + : "=c" (ecx) + : "a" (field) + : "memory"); + + return ecx; +} + +static inline void __vmwrite(unsigned long field, unsigned long value) +{ + __asm__ __volatile__ ( VMWRITE_OPCODE + MODRM_EAX_ECX + /* CF==1 or ZF==1 --> crash (ud2) */ + "ja 1f ; ud2 ; 1:\n" + : + : "a" (field) , "c" (value) + : "memory"); +} + +static inline unsigned long __vmread_safe(unsigned long field, int *error) +{ + unsigned long ecx; + + __asm__ __volatile__ ( VMREAD_OPCODE + MODRM_EAX_ECX + /* CF==1 or ZF==1 --> rc = -1 */ + "setna %b0 ; neg %0" + : "=q" (*error), "=c" (ecx) + : "0" (0), "a" (field) + : "memory"); + + return ecx; +} + +static inline void __vmlaunch (void) +{ + __asm__ __volatile__ ( VMLAUNCH_OPCODE + ::: "memory"); +} + +static inline void __vmresume (void) +{ + __asm__ __volatile__ ( VMRESUME_OPCODE + ::: "memory"); +} + +static inline void __vmxoff (void) +{ + __asm__ __volatile__ ( VMXOFF_OPCODE + ::: "memory"); +} + +static inline int __vmxon (uint64_t addr) +{ + int rc; + + __asm__ __volatile__ ( VMXON_OPCODE + MODRM_EAX_06 + /* CF==1 or ZF==1 --> rc = -1 */ + "setna %b0 ; neg %0" + : "=q" (rc) + : "0" (0), "a" (&addr) + : "memory"); + + return rc; +} + +extern void handle_init_sipi_sipi(void); + +#endif /* __TXT_VMCS_H__ */ + + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r 419625d61514 -r de5826b5b302 sboot/include/types.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sboot/include/types.h Fri Jun 08 16:57:19 2007 -0700 @@ -0,0 +1,54 @@ +#ifndef __TYPES_H__ +#define __TYPES_H__ + +#include +#include + +#define BITS_TO_LONGS(bits) \ + (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG) +#define DECLARE_BITMAP(name,bits) \ + unsigned long name[BITS_TO_LONGS(bits)] + +#ifndef NULL +#define NULL ((void*)0) +#endif + +#define INT_MAX ((int)(~0U>>1)) +#define INT_MIN (-INT_MAX - 1) +#define UINT_MAX (~0U) +#define LONG_MAX ((long)(~0UL>>1)) +#define LONG_MIN (-LONG_MAX - 1) +#define ULONG_MAX (~0UL) + +#ifndef __ASSEMBLY__ + +/* bsd */ +typedef unsigned char u_char; +typedef unsigned short u_short; +typedef unsigned int u_int; +typedef unsigned long u_long; + +/* sysv */ +typedef unsigned char unchar; +typedef unsigned short ushort; +typedef unsigned int uint; +typedef unsigned long ulong; + +typedef __u8 uint8_t; +typedef __u8 u_int8_t; +typedef __s8 int8_t; + +typedef __u16 uint16_t; +typedef __u16 u_int16_t; +typedef __s16 int16_t; + +typedef __u32 uint32_t; +typedef __u32 u_int32_t; +typedef __s32 int32_t; + +typedef __u64 uint64_t; +typedef __u64 u_int64_t; +typedef __s64 int64_t; +#endif /* __ASSEMBLY__ */ + +#endif /* __TYPES_H__ */ diff -r 419625d61514 -r de5826b5b302 sboot/include/uuid.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sboot/include/uuid.h Fri Jun 08 16:57:19 2007 -0700 @@ -0,0 +1,74 @@ +/* + * uuid.h: support functions for UUIDs + * + * Copyright (c) 2006-2007, 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 __UUID_H__ +#define __UUID_H__ + +typedef struct __attribute__ ((__packed__)) { + uint32_t data1; + uint16_t data2; + uint16_t data3; + uint16_t data4; + uint8_t data5[6]; +} uuid_t; + +static inline bool are_uuids_equal(const uuid_t *uuid1, const uuid_t *uuid2) +{ + return (memcmp(uuid1, uuid2, sizeof(*uuid1)) == 0); +} + +static inline void print_uuid(const uuid_t *uuid) +{ + printk("{0x%08x, 0x%04x, 0x%04x, 0x%04x,\n" + "\t\t{0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x}}", + uuid->data1, (uint32_t)uuid->data2, (uint32_t)uuid->data3, + (uint32_t)uuid->data4, (uint32_t)uuid->data5[0], + (uint32_t)uuid->data5[1], (uint32_t)uuid->data5[2], + (uint32_t)uuid->data5[3], (uint32_t)uuid->data5[4], + (uint32_t)uuid->data5[5]); +} + +#endif /* __UUID_H__ */ + + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r 419625d61514 -r de5826b5b302 sboot/include/x86_types.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sboot/include/x86_types.h Fri Jun 08 16:57:19 2007 -0700 @@ -0,0 +1,49 @@ +#ifndef __X86_TYPES_H__ +#define __X86_TYPES_H__ + +#ifndef __ASSEMBLY__ + +#include + +typedef __signed__ char __s8; +typedef unsigned char __u8; + +typedef __signed__ short __s16; +typedef unsigned short __u16; + +typedef __signed__ int __s32; +typedef unsigned int __u32; + +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) +typedef __signed__ long long __s64; +typedef unsigned long long __u64; +#endif + +typedef signed char s8; +typedef unsigned char u8; + +typedef signed short s16; +typedef unsigned short u16; + +typedef signed int s32; +typedef unsigned int u32; + +typedef signed long long s64; +typedef unsigned long long u64; +#if defined(CONFIG_X86_PAE) +typedef u64 paddr_t; +#define PRIpaddr "016llx" +#else +typedef unsigned long paddr_t; +#define PRIpaddr "08lx" +#endif + +typedef unsigned long size_t; + +#endif /* __ASSEMBLY__ */ + +#define BITS_PER_LONG 32 +#define BYTES_PER_LONG 4 +#define LONG_BYTEORDER 2 + +#endif /* __X86_TYPES_H__ */ diff -r 419625d61514 -r de5826b5b302 sboot/txt/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sboot/txt/Makefile Fri Jun 08 16:57:19 2007 -0700 @@ -0,0 +1,8 @@ +obj-y += errors.o +obj-y += txt.o +obj-y += verify.o +obj-y += mtrrs.o +obj-y += acmod.o +obj-y += verify.o +obj-y += vmcs.o + diff -r 419625d61514 -r de5826b5b302 sboot/txt/acmod.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sboot/txt/acmod.c Fri Jun 08 16:57:19 2007 -0700 @@ -0,0 +1,537 @@ +/* + * acmod.c: support functions for use of Intel(r) TXT Authenticated + * Code (AC) Modules + * + * Copyright (c) 2003-2007, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + union { + struct { + uint8_t chipset_acm_type; + uint8_t version; + uint16_t length; + uint32_t chipset_id_list; + } v1; + }; +} acm_info_table_t; + + +/* chipset_acm_type field values */ +#define ACM_CHIPSET_TYPE_SINIT 0x01 + +typedef struct { + uint32_t flags; + uint16_t vendor_id; + uint16_t device_id; + uint16_t revision_id; + uint16_t reserved; + uint32_t extended_id; +} acm_chipset_id_t; + +typedef struct { + uint32_t count; + acm_chipset_id_t chipset_id[]; +} acm_chipset_id_list_t; + + +#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 { + uint32_t mask; + uint32_t version; + } acm_versions[MAX_SUPPORTED_ACM_VERSIONS]; + int n_versions; + uint32_t acm_max_size; + uint32_t acm_mem_types; + uint32_t 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 bool get_parameters(getsec_parameters_t *params) +{ + unsigned long cr4; + uint32_t index, eax, ebx, ecx; + int param_type; + + /* sanity check because GETSEC[PARAMETERS] will fail if not set */ + cr4 = read_cr4(); + if ( !(cr4 & X86_CR4_SMXE) ) { + printk("SMXE not enabled, can't read parameters\n"); + return false; + } + + memset(params, 0, sizeof(*params)); + params->acm_max_size = DEF_ACM_MAX_SIZE; + params->acm_mem_types = DEF_ACM_MEM_TYPES; + params->senter_controls = DEF_SENTER_CTRLS; + 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("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("unknown GETSEC[PARAMETERS] type: %d\n", param_type); + param_type = 0; /* set so that we break out of the loop */ + } + } while ( param_type != 0 ); + + if ( params->n_versions == 0 ) { + params->acm_versions[0].mask = DEF_ACM_VER_MASK; + params->acm_versions[0].version = DEF_ACM_VER_SUPPORTED; + params->n_versions = 1; + } + + return true; +} + +static acm_info_table_t *get_acmod_info_table(acm_hdr_t* hdr) +{ + uint32_t user_area_off; + + /* this fn assumes that the ACM has already passed at least the initial */ + /* is_acmod() checks */ + + user_area_off = (hdr->header_len + hdr->scratch_size) * 4; + /* check that table is within module */ + if ( user_area_off + sizeof(acm_info_table_t) > hdr->size*4 ) { + printk("ACM info table size too large: %x\n", + user_area_off + sizeof(acm_info_table_t)); + return NULL; + } + + return (acm_info_table_t *)((uint32_t)hdr + user_area_off); +} + +static void print_acm_hdr(acm_hdr_t *hdr, const char *mod_name) +{ + acm_info_table_t *info_table; + + printk("AC module header dump for %s:\n", + (mod_name == NULL) ? "?" : mod_name); + printk("\t type=%x\n", hdr->module_type); + printk("\t length=%x\n", hdr->header_len); + printk("\t version=%x\n", hdr->header_ver); + printk("\t id=%x\n", hdr->module_id); + printk("\t vendor=%x\n", hdr->module_vendor); + printk("\t date=%08x\n", hdr->date); + printk("\t size*4=%x\n", hdr->size*4); + printk("\t entry point=%08x:%08x\n", hdr->seg_sel, + hdr->entry_point); + printk("\t scratch_size=%x\n", hdr->scratch_size); + + printk("\t info_table:\n"); + info_table = get_acmod_info_table(hdr); + if ( info_table == NULL ) { + printk("\t\t \n"); + return; + } + printk("\t\tchipset_acm_type=%x\n", + (uint32_t)info_table->v1.chipset_acm_type); + printk("\t\tversion=%x\n", (uint32_t)info_table->v1.version); + printk("\t\tlength=%x\n", (uint32_t)info_table->v1.length); + printk("\t\tchipset_id_list=%x\n", + (uint32_t)info_table->v1.chipset_id_list); +} + +uint32_t get_supported_os_sinit_data_ver(acm_hdr_t* hdr) +{ + acm_info_table_t *info_table; + + /* assumes that it passed is_sinit_acmod() */ + + info_table = get_acmod_info_table(hdr); + if ( info_table == NULL ) + return 0x00; + + return 0x01; +} + +static bool is_acmod(void *acmod_base, uint32_t acmod_size, uint8_t *type) +{ + acm_hdr_t *acm_hdr; + acm_info_table_t *info_table; + + acm_hdr = (acm_hdr_t *)acmod_base; + + /* first check size */ + if ( acmod_size < sizeof(acm_hdr_t) ) { + printk("ACM size is too small: acmod_size=%x," + " sizeof(acm_hdr)=%x\n", acmod_size, sizeof(acm_hdr) ); + return false; + } + if ( acmod_size != acm_hdr->size * 4 ) { + printk("ACM size is too small: acmod_size=%x," + " acm_hdr->size*4=%x\n", acmod_size, acm_hdr->size*4); + return false; + } + + /* then check type and vendor */ + if ( (acm_hdr->module_type != ACM_TYPE_CHIPSET) || + (acm_hdr->module_vendor != ACM_VENDOR_INTEL) ) { + printk("ACM type/vendor mismatch: module_type=%x," + " module_vendor=%x\n", acm_hdr->module_type, + acm_hdr->module_vendor); + return false; + } + + info_table = get_acmod_info_table(acm_hdr); + if ( info_table == NULL ) + return false; + + if ( type != NULL ) + *type = info_table->v1.chipset_acm_type; + /* there is forward compatibility, so this is just a warning */ + if ( info_table->v1.version != 0x01 ) + printk("ACM info_table version mismatch (%x)\n", + (unsigned int)info_table->v1.version); + + return true; +} + +bool is_sinit_acmod(void *acmod_base, uint32_t acmod_size) +{ + uint8_t type; + + if ( !is_acmod(acmod_base, acmod_size, &type) ) + return false; + + if ( type != ACM_CHIPSET_TYPE_SINIT ) { + printk("ACM is not an SINIT ACM (%x)\n", type); + return false; + } + + return true; +} + +bool does_acmod_match_chipset(acm_hdr_t* hdr) +{ + acm_info_table_t *info_table; + acm_chipset_id_list_t *chipset_id_list; + acm_chipset_id_t *chipset_id; + txt_didvid_t didvid; + uint32_t size, id_list_off; + int i; + + /* this fn assumes that the ACM has already passed the is_acmod() checks */ + + info_table = get_acmod_info_table(hdr); + if ( info_table == NULL ) + return false; + id_list_off = info_table->v1.chipset_id_list; + + size = hdr->size * 4; + + /* check that chipset id table is w/in ACM */ + if ( id_list_off + sizeof(acm_chipset_id_t) > size ) { + printk("ACM chipset id list is too big: chipset_id_list=%x\n", + id_list_off); + return false; + } + + chipset_id_list = (acm_chipset_id_list_t *)((uint32_t)hdr + id_list_off); + + /* check that all entries are w/in ACM */ + if ( id_list_off + sizeof(acm_chipset_id_t) + + chipset_id_list->count * sizeof(acm_chipset_id_t) > size ) { + printk("ACM chipset id entries are too big:" + " chipset_id_list->count=%x\n", chipset_id_list->count); + return false; + } + + /* get chipset device and vendor id info */ + didvid._raw = read_pub_config_reg(TXTCR_DIDVID); + printk("chipset ids: vendor=%x, device=%x, revision=%x\n", + didvid.vendor_id, didvid.device_id, didvid.revision_id); + + printk("%x ACM chipset id entries:\n", chipset_id_list->count); + for ( i = 0; i < chipset_id_list->count; i++ ) { + chipset_id = &(chipset_id_list->chipset_id[i]); + printk("\tvendor=%x, device=%x, flags=%x, revision=%x, " + "extended=%x\n", (uint32_t)chipset_id->vendor_id, + (uint32_t)chipset_id->device_id, chipset_id->flags, + (uint32_t)chipset_id->revision_id, chipset_id->extended_id); + + if ( (didvid.vendor_id == chipset_id->vendor_id ) && + (didvid.device_id == chipset_id->device_id ) && + ( ( ( (chipset_id->flags & 0x1) == 0) && + (didvid.revision_id == chipset_id->revision_id) ) || + ( ( (chipset_id->flags & 0x1) == 1) && + ((didvid.revision_id & chipset_id->revision_id) != 0 ) ) ) ) + return true; + } + + printk("ACM does not match chipset\n"); + +#ifdef CHIPSET_REVID_BUG + return true; +#else + return false; +#endif +} + +acm_hdr_t *copy_sinit(acm_hdr_t *sinit) +{ + void *sinit_region_base; + uint32_t sinit_region_size; + txt_heap_t *txt_heap; + bios_os_data_t *bios_os_data; + + /* get BIOS-reserved region from LT.SINIT.BASE config reg */ + sinit_region_base = (void*)(uint32_t)read_pub_config_reg(TXTCR_SINIT_BASE); + sinit_region_size = (uint32_t)read_pub_config_reg(TXTCR_SINIT_SIZE); + + /* + * check if BIOS already loaded an SINIT module there + */ + txt_heap = get_txt_heap(); + bios_os_data = get_bios_os_data_start(txt_heap); + /* BIOS has loaded an SINIT module, so verify that it is valid */ + if ( bios_os_data->bios_sinit_size != 0 ) { + printk("BIOS has already loaded an SINIT module\n"); + /* is it a valid SINIT module? */ + if ( is_sinit_acmod(sinit_region_base, + bios_os_data->bios_sinit_size) ) { + /* is it newer than the one we've been provided? */ + if ( ((acm_hdr_t *)sinit_region_base)->date >= sinit->date ) + return (acm_hdr_t *)sinit_region_base; /* yes */ + else + printk("BIOS SINIT is older: date=%x\n", + ((acm_hdr_t *)sinit_region_base)->date); + } + } + /* our SINIT is newer than BIOS's (or BIOS did not have one) */ + + /* make sure our SINIT fits in the reserved region */ + if ( (sinit->size * 4) > sinit_region_size ) { + printk("BIOS-reserved SINIT size (%x) is too small for loaded " + "SINIT (%x)\n", sinit_region_size, sinit->size*4); + return NULL; + } + + /* copy it there */ + memcpy(sinit_region_base, sinit, sinit->size*4); + + printk("copied SINIT (size=%x) to %p\n", sinit->size*4, + sinit_region_base); + + return (acm_hdr_t *)sinit_region_base; +} + + +/* + * Do some AC module sanity checks because any violations will cause + * an TXT.RESET. Instead detect these, print a desriptive message, + * and skip SENTER/ENTERACCS + */ +bool verify_acmod(acm_hdr_t *acm_hdr) +{ + getsec_parameters_t params; + uint32_t size; + + /* assumes this already passed is_acmod() test */ + + size = acm_hdr->size * 4; /* hdr size is in dwords, we want bytes */ + + /* + * AC mod must start on 4k page boundary + */ + + if ( (unsigned long)acm_hdr & 0xfff ) { + printk("AC mod base not 4K aligned (%p)\n", acm_hdr); + return false; + } + printk("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("AC mod size %x bogus\n", size); + return false; + } + + if ( get_parameters(¶ms) == -1 ) { + printk("get_parameters() failed\n"); + return false; + } + + if ( size > params.acm_max_size ) { + printk("AC mod size too large: %x (max=%x)\n", size, + params.acm_max_size); + return false; + } + + printk("AC mod size OK\n"); + + /* + * perform checks on AC mod structure + */ + + /* print it for debugging */ + print_acm_hdr(acm_hdr, "SINIT"); + + /* entry point is offset from base addr so make sure it is within module */ + if ( acm_hdr->entry_point >= size ) { + printk("AC mod entry (%08x) >= AC mod size (%08x)\n", + acm_hdr->entry_point, size); + return false; + } + + if ( !acm_hdr->seg_sel || /* invalid selector */ + (acm_hdr->seg_sel & 0x07) || /* LDT, PL!=0 */ + (acm_hdr->seg_sel + 8 > acm_hdr->gdt_limit) ) { + printk("AC mod selector [%04x] bogus\n", acm_hdr->seg_sel); + return false; + } + + return true; +} + +/* + * this must be done for each processor so that all have the same + * memory types + */ +void set_mtrrs_for_acmod(acm_hdr_t *hdr) +{ + 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); + + /* disable MTRRs */ + set_all_mtrrs(false); + + /* + * now set MTRRs for AC mod and rest of memory + */ + set_mem_type(hdr, hdr->size*4, MTRR_TYPE_WRBACK); + + /* + * now undo some of earlier changes and enable our new settings + */ + + /* flush caches */ + wbinvd(); + + /* enable MTRRs */ + set_all_mtrrs(true); + + /* restore CR0 (cacheing) */ + write_cr0(cr0); + + /* restore CR4 (global pages) */ + write_cr4(cr4); + + /* enable interrupts */ + __restore_flags(eflags); +} + + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r 419625d61514 -r de5826b5b302 sboot/txt/errors.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sboot/txt/errors.c Fri Jun 08 16:57:19 2007 -0700 @@ -0,0 +1,113 @@ +/* + * errors.c: parse and return status of Intel(r) TXT error codes + * + * Copyright (c) 2003-2007, 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 + + +static void display_errors(void) +{ + txt_errorcode_t err; + txt_ests_t ests; + txt_e2sts_t e2sts; + txt_errorcode_sw_t sw_err; + acmod_error_t acmod_err; + + /* + * display LT.ERRORODE error + */ + err = (txt_errorcode_t)read_pub_config_reg(TXTCR_ERRORCODE); + printk("LT.ERRORCODE=%Lx\n", err._raw); + + /* AC module error (don't know how to parse other errors) */ + if ( err.valid ) { + if ( err.external == 0 ) /* processor error */ + printk("\t processor error %x\n", (uint32_t)err.type); + else { /* external SW error */ + sw_err._raw = err.type; + if ( sw_err.src == 1 ) /* unknown SW error */ + printk("unknown SW error %x\n", (uint32_t)sw_err.err); + else { /* ACM error */ + acmod_err._raw = sw_err.err; + printk("AC module error : type=%x, progress=%02x, error=%x\n", + (uint32_t)acmod_err.type, (uint32_t)acmod_err.progress, + (uint32_t)acmod_err.error); + } + } + } + + /* + * display LT.ESTS error + */ + ests = (txt_ests_t)read_pub_config_reg(TXTCR_ESTS); + printk("LT.ESTS=%Lx\n", ests._raw); + + /* + * display LT.E2STS error + * - only valid if LT.WAKE-ERROR.STS set in LT.STS reg + */ + if ( ests.txt_wake_error_sts ) { + e2sts = (txt_e2sts_t)read_pub_config_reg(TXTCR_E2STS); + printk("LT.E2STS=%Lx\n", e2sts._raw); + } +} + +bool txt_get_error(void) +{ + txt_errorcode_t err; + + display_errors(); + + err = (txt_errorcode_t)read_pub_config_reg(TXTCR_ERRORCODE); + if ( err.valid ) + return false; + else + return true; +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r 419625d61514 -r de5826b5b302 sboot/txt/mtrrs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sboot/txt/mtrrs.c Fri Jun 08 16:57:19 2007 -0700 @@ -0,0 +1,193 @@ +/* + * mtrrs.c: support functions for manipulating MTRRs + * + * Copyright (c) 2003-2007, 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 + +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("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 + */ +bool set_mem_type(void *base, uint32_t size, uint32_t 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("setting MTRRs for acmod: base=%p, size=%x, num_pages=%d\n", + base, size, num_pages); + + while ( num_pages > 0 ) { + uint32_t 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("exceeded number of var MTRRs when mapping range\n"); + return false; + } + } + + return true; +} + +/* 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 419625d61514 -r de5826b5b302 sboot/txt/txt.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sboot/txt/txt.c Fri Jun 08 16:57:19 2007 -0700 @@ -0,0 +1,580 @@ +/* + * txt.c: Intel(r) TXT support functions, including initiating measured + * launch, post-launch, AP wakeup, etc. + * + * Copyright (c) 2003-2007, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern char _stext[]; /* start of text section */ +extern char __start[]; /* sboot entry point in boot.S */ +extern char _txt_wakeup[]; /* RLP join address for GETSEC[WAKEUP] */ +extern char _end[]; /* end of module */ + +/* MLE/kernel shared data page (in boot.S) */ +extern mle_kernel_shared_t _mle_kernel_shared; + +/* + * this is the structure whose addr we'll put in TXT heap + */ +static mle_hdr_t g_mle_hdr = { + guid : {0x9082ac5a, 0x74a7476f, 0xa2555c0f, 0x42b651cb}, + length : sizeof(mle_hdr_t), + version : 0x00010000, + entry_point : (uint32_t)&__start - SBOOT_BASE_ADDR, + req_mem_size : 0, /* we don't use this */ + features : 0x00000000 /* nor this */ +}; + +static void print_file_info(void) +{ + printk("file addresses:\n"); + printk("\t &_stext=%p\n", &_stext); + printk("\t &__start=%p\n", &__start); + printk("\t &_end=%p\n", &_end); + printk("\t &_txt_wakeup=%p\n", &_txt_wakeup); + printk("\t &g_mle_hdr=%p\n", &g_mle_hdr); +} + +static void print_mle_hdr(mle_hdr_t *mle_hdr) +{ + printk("MLE header:\n"); + printk("\t guid="); print_uuid((uuid_t *)mle_hdr->guid); printk("\n"); + printk("\t length=%x\n", mle_hdr->length); + printk("\t version=%08x\n", mle_hdr->version); + printk("\t entry_point=%08x\n", mle_hdr->entry_point); + printk("\t req_mem_size=%x\n", mle_hdr->req_mem_size); + printk("\t features=%08x\n", mle_hdr->features); +} + +/* + * build_mle_pagetable() + */ + +/* page dir/table entry is phys addr + P + R/W + PWT */ +#define MAKE_PDTE(addr) (((uint64_t)(unsigned long)(addr) & PAGE_MASK) | 0x01) + +/* we assume/know that our image is <2MB and thus fits w/in a single */ +/* PT (512*4KB = 2MB) and thus fixed to 1 pg dir ptr and 1 pgdir and */ +/* 1 ptable = 3 pages and just 1 loop loop for ptable MLE page table */ +/* can only contain 4k pages */ + +static void *build_mle_pagetable(uint32_t mle_start, uint32_t mle_end) +{ + void *ptab_base; + uint32_t mle_size, ptab_size, mle_off; + void *pg_dir_ptr_tab, *pg_dir, *pg_tab; + uint64_t *pte; + + mle_size = mle_end - mle_start; + printk("MLE start=%x, end=%x, size=%x\n", mle_start, mle_end, + mle_size); + if ( mle_size > 512*PAGE_SIZE ) { + printk("MLE size too big for single page table\n"); + return NULL; + } + + + /* should start on page boundary */ + if ( mle_start & ~PAGE_MASK ) { + printk("MLE start is not page-aligned\n"); + return NULL; + } + + /* place ptab_base below MLE */ + ptab_size = 3 * PAGE_SIZE; /* pgdir ptr + pgdir + ptab = 3 */ + ptab_base = (void *)((mle_start - ptab_size) & PAGE_MASK); + memset(ptab_base, 0, ptab_size); + printk("ptab_size=%x, ptab_base=%p\n", ptab_size, ptab_base); + + pg_dir_ptr_tab = ptab_base; + pg_dir = pg_dir_ptr_tab + PAGE_SIZE; + pg_tab = pg_dir + PAGE_SIZE; + + /* only use first entry in page dir ptr table */ + *(uint64_t *)pg_dir_ptr_tab = MAKE_PDTE(pg_dir); + + /* only use first entry in page dir */ + *(uint64_t *)pg_dir = MAKE_PDTE(pg_tab); + + pte = pg_tab; + mle_off = 0; + do { + *pte = MAKE_PDTE(mle_start + mle_off); + + pte++; + mle_off += PAGE_SIZE; + } while ( mle_off < mle_size ); + + return ptab_base; +} + +/* size can be NULL */ +static bool find_sinit(multiboot_info_t *mbi, void **base, uint32_t *size) +{ + module_t *mods; + uint32_t size2 = 0; + void *base2 = NULL; + int i; + + if ( base == NULL ) { + printk("find_sinit() base is NULL\n"); + return false; + } + *base = NULL; + if ( size != NULL ) + *size = 0; + + if ( mbi->mods_addr == 0 || mbi->mods_count == 0 ) { + printk("no module info\n"); + return false; + } + + mods = (module_t *)(mbi->mods_addr); + for ( i = mbi->mods_count - 1; i > 0; i-- ) { + base2 = (void *)mods[i].mod_start; + size2 = mods[i].mod_end - (unsigned long)(base2); + /* check if this is really an SINIT AC module */ + if ( is_sinit_acmod(base2, size2) ) + break; + } + /* not found */ + if ( i == 0 ) { + printk("no SINIT AC module found\n"); + return false; + } + + *base = base2; + if ( size != NULL ) + *size = size2; + return true; +} + +/* + * sets up TXT heap + */ +static txt_heap_t *init_txt_heap(void *ptab_base, acm_hdr_t *sinit, + multiboot_info_t *mbi) +{ + txt_heap_t *txt_heap; + os_mle_data_t *os_mle_data; + os_sinit_data_t *os_sinit_data; + uint64_t *size; + uint32_t os_sinit_data_ver; + + txt_heap = get_txt_heap(); + + /* + * BIOS to OS/loader data already setup by BIOS + */ + if ( !verify_txt_heap(txt_heap, true) ) + return NULL; + + /* + * OS/loader to MLE data + */ + os_mle_data = get_os_mle_data_start(txt_heap); + size = (uint64_t *)((uint32_t)os_mle_data - sizeof(uint64_t)); + *size = sizeof(*os_mle_data) + sizeof(uint64_t); + memset(os_mle_data, 0, sizeof(*os_mle_data)); + os_mle_data->version = 0x01; + os_mle_data->mbi = mbi; + + /* + * OS/loader to SINIT data + */ + os_sinit_data_ver = get_supported_os_sinit_data_ver(sinit); + printk("SINIT supports os_sinit_data version %x\n", + os_sinit_data_ver); + /* warn if SINIT supports more recent OS to SINIT data version than us */ + if ( os_sinit_data_ver > 0x01 ) + printk("SINIT's os_sinit_data version unsupported (%x)\n", + os_sinit_data_ver); + os_sinit_data = get_os_sinit_data_start(txt_heap); + size = (uint64_t *)((uint32_t)os_sinit_data - sizeof(uint64_t)); + *size = sizeof(*os_sinit_data) + sizeof(uint64_t); + memset(os_sinit_data, 0, sizeof(*os_sinit_data)); + /* common to all versions */ + /* this is phys addr */ + os_sinit_data->mle_ptab = (uint64_t)(unsigned long)ptab_base; + os_sinit_data->mle_size = (uint64_t)&_end - (uint64_t)&_stext; + /* this is linear addr (offset from MLE base) of mle header */ + os_sinit_data->mle_hdr_base = (uint64_t)&g_mle_hdr - (uint64_t)&_stext; + os_sinit_data->version = 0x01; + print_os_sinit_data(os_sinit_data); + + /* + * SINIT to MLE data will be setup by SINIT + */ + + return txt_heap; +} + +static void txt_wakeup_cpus(void) +{ + struct { + uint16_t limit; + uint32_t base; + } gdt; + uint16_t cs; + mle_join_t mle_join; + + /* RLPs will use our GDT and CS */ + __asm__ __volatile__ ("sgdt (%0) \n" :: "a"(&gdt) : "memory"); + __asm__ __volatile__ ("movl %%cs, %0\n" : "=r"(cs)); + + mle_join.entry_point = (uint32_t)(unsigned long)&_txt_wakeup; + mle_join.seg_sel = cs; + mle_join.gdt_base = gdt.base; + mle_join.gdt_limit = gdt.limit; + + printk("mle_join.entry_point = %x\n", mle_join.entry_point); + printk("mle_join.seg_sel = %x\n", mle_join.seg_sel); + printk("mle_join.gdt_base = %x\n", mle_join.gdt_base); + printk("mle_join.gdt_limit = %x\n", mle_join.gdt_limit); + + write_priv_config_reg(TXTCR_MLE_JOIN, (uint64_t)(unsigned long)&mle_join); + + printk("joining RLPs to MLE with GETSEC[WAKEUP]\n"); + __getsec_wakeup(); + + /* TBD: maybe need wait here for AP to launch mini guest */ + + printk("GETSEC[WAKEUP] completed\n"); +} + +bool txt_is_launched(void) +{ + txt_sts_t sts; + + sts._raw = read_pub_config_reg(TXTCR_STS); + + return sts.senter_done_sts; +} + +bool txt_launch_environment(multiboot_info_t *mbi) +{ + acm_hdr_t *sinit; + void *mle_ptab_base; + os_mle_data_t *os_mle_data; + txt_heap_t *txt_heap; + + /* + * find SINIT AC module in modules list (it should be one of last three) + */ + if ( !find_sinit(mbi, (void **)&sinit, NULL) ) + return false; + + /* check if it matches chipset */ + if ( !does_acmod_match_chipset(sinit) ) { + printk("SINIT does not match chipset\n"); + return false; + } + + /* if it is newer than BIOS-provided version, then copy it to */ + /* BIOS reserved region */ + sinit = copy_sinit(sinit); + if ( sinit == NULL ) + return false; + + /* do some checks on it */ + if ( !verify_acmod(sinit) ) + return false; + + /* print some debug info */ + print_file_info(); + print_mle_hdr(&g_mle_hdr); + + /* create MLE page table */ + mle_ptab_base = build_mle_pagetable((uint32_t)&_stext, (uint32_t)&_end); + if ( mle_ptab_base == NULL ) + return false; + + /* initialize TXT heap */ + txt_heap = init_txt_heap(mle_ptab_base, sinit, mbi); + + /* save MTRRs before we alter them for SINIT launch */ + os_mle_data = get_os_mle_data_start(txt_heap); + save_mtrrs(&(os_mle_data->saved_mtrr_state)); + + /* set MTRRs properly for AC module (SINIT) */ + set_mtrrs_for_acmod(sinit); + + printk("executing GETSEC[SENTER]...\n"); + __getsec_senter((uint32_t)sinit, (sinit->size)*4); + printk("ERROR--we should not get here!\n"); + return false; +} + +bool txt_prepare_platform(void) +{ + tpm_unit_test_before_senter(); + if ( is_tpm_ready(0) ) + return true; + else + return false; +} + +bool txt_prepare_cpu(void) +{ + unsigned long eflags, cr0; + uint64_t mcg_cap, mcg_stat; + int i; + + /* must be running at CPL 0 => this is implicit in even getting this far */ + /* since our bootstrap code loads a GDT, etc. */ + + cr0 = read_cr0(); + + /* must be in protected mode */ + if ( !(cr0 & X86_CR0_PE) ) { + printk("ERR: not in protected mode\n"); + return false; + } + + /* cache must be enabled (CR0.CD = CR0.NW = 0) */ + if ( cr0 & X86_CR0_CD ) { + printk("CR0.CD set\n"); + cr0 &= ~X86_CR0_CD; + } + if ( cr0 & X86_CR0_NW ) { + printk("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("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("EFLAGS.VM set\n"); + __restore_flags(eflags | ~X86_EFLAGS_VM); + } + + printk("CR0 and EFLAGS OK\n"); + + /* + * verify that we're not already in a protected environment + */ + if ( txt_is_launched() ) { + printk("already in protected environment\n"); + return false; + } + + /* + * 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("machine check in progress\n"); + return false; + } + + /* 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("MCG[%d] = %Lx ERROR\n", i, mcg_stat); + return false; + } + } + + printk("no machine check errors\n"); + + /* all is well with the processor state */ + printk("CPU is ready for SENTER\n"); + + return true; +} + +bool txt_post_launch(void) +{ + txt_heap_t *txt_heap; + os_mle_data_t *os_mle_data; + + /* TBD: need to handle this gracefully */ + if ( !txt_post_launch_verify_platform() ) + printk("failed to verify platform\n"); + + /* clear error config registers so that we start fresh */ + write_priv_config_reg(TXTCR_ERRORCODE, 0x00000000); + write_priv_config_reg(TXTCR_ESTS, 0xffffffff); /* write 1's to clear */ + + tpm_unit_test_after_senter(); + + /* always set the LT.CMD.SECRETS flag */ + write_priv_config_reg(TXTCR_CMD_SECRETS, 0x01); + read_priv_config_reg(TXTCR_E2STS); /* just a fence, so ignore return */ + printk("set LT.CMD.SECRETS flag\n"); + + /* get saved OS state (os_mvmm_data_t) from LT heap */ + txt_heap = get_txt_heap(); + os_mle_data = get_os_mle_data_start(txt_heap); + + /* restore pre-SENTER MTRRs that were overwritten for SINIT launch */ + /* TBD: we need to validate these before restoring them */ + restore_mtrrs(&(os_mle_data->saved_mtrr_state)); + + /* bring RLPs into environment */ + txt_wakeup_cpus(); + + /* enable SMIs (do this after APs have been awakened and sync'ed w/ BSP) */ + __getsec_smctrl(); + + return true; +} + +void txt_cpu_wakeup(uint32_t cpuid) +{ + txt_heap_t *txt_heap; + os_mle_data_t *os_mle_data; + + printk("cpu %x waking up from TXT sleep\n", cpuid); + + txt_heap = get_txt_heap(); + os_mle_data = get_os_mle_data_start(txt_heap); + + /* apply (validated) (pre-SENTER) MTRRs from BSP to each AP */ + restore_mtrrs(&(os_mle_data->saved_mtrr_state)); + + handle_init_sipi_sipi(); +} + +bool txt_protect_mem_regions(void) +{ + uint64_t base, size; + + /* + * TXT has 2 regions of RAM that need to be reserved for use by only the + * hypervisor; not even dom0 should have access: + * TXT heap, SINIT AC module + */ + + /* TXT heap */ + base = read_pub_config_reg(TXTCR_HEAP_BASE); + size = read_pub_config_reg(TXTCR_HEAP_SIZE); + printk("protecting TXT heap (%Lx - %Lx) in e820 table\n", base, + (base + size - 1)); + if ( !e820_protect_region(base, size, E820_PROTECTED) ) + return false; + + /* SINIT */ + base = read_pub_config_reg(TXTCR_SINIT_BASE); + size = read_pub_config_reg(TXTCR_SINIT_SIZE); + printk("protecting SINIT (%Lx - %Lx) in e820 table\n", base, + (base + size - 1)); + if ( !e820_protect_region(base, size, E820_PROTECTED) ) + return false; + + /* TBD: we will need to parse sinit_mle_data.mdrs records and ensure */ + /* that we don't use inappropriate memory for domains */ + +#if 0 + /* + * some BIOSes mark the TPM and LT public space as reserved + * this will cause xen to give these regions to dom_io instead of dom0 + * however, if we mark them as protected, then they won't be given + * to dom_io and dom0 will be allowed to map them as MMIO (not as RAM) + * this should have no effect on system's whose BIOS doesn't do this + */ + + /* TPM localities */ + base = TPM_LOCALITY_BASE; + size = NR_TPM_LOCALITY_PAGES * PAGE_SIZE; + printk("protecting TPM localities (%Lx - %Lx) in e820 table\n", + base, (base + size - 1)); + if ( !e820_protect_region(base, size, E820_PROTECTED) ) + return false; + + /* TXT public space */ + base = TXT_PUB_CONFIG_REGS_BASE; + size = NR_TXT_CONFIG_PAGES * PAGE_SIZE; + printk("protecting TXT Public Space (%Lx - %Lx) in e820 table\n", + base, (base + size - 1)); + if ( !e820_protect_region(base, size, E820_PROTECTED) ) + return false; +#endif + + /* TXT private space */ + base = TXT_PRIV_CONFIG_REGS_BASE; + size = NR_TXT_CONFIG_PAGES * PAGE_SIZE; + printk("protecting TXT Private Space (%Lx - %Lx) in e820 table\n", + base, (base + size - 1)); + if ( !e820_protect_region(base, size, E820_PROTECTED) ) + return false; + + return true; +} + + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r 419625d61514 -r de5826b5b302 sboot/txt/verify.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sboot/txt/verify.c Fri Jun 08 16:57:19 2007 -0700 @@ -0,0 +1,489 @@ +/* + * verify.c: verify that platform and processor supports Intel(r) TXT + * + * Copyright (c) 2003-2007, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern char _stext[]; /* start of text section */ +extern char _end[]; /* end of module */ + +/* + * CPUID extended feature info + */ +static unsigned int g_cpuid_ext_feat_info; + +/* + * IA32_FEATURE_CONTROL_MSR + */ +static unsigned long g_feat_ctrl_msr; + + +static void read_processor_info(void) +{ + unsigned long f1, f2; + + /* is CPUID supported? */ + /* (it's supported if ID flag in EFLAGS can be set and cleared) */ + asm("pushf\n\t" + "pushf\n\t" + "pop %0\n\t" + "mov %0,%1\n\t" + "xor %2,%0\n\t" + "push %0\n\t" + "popf\n\t" + "pushf\n\t" + "pop %0\n\t" + "popf\n\t" + : "=&r" (f1), "=&r" (f2) + : "ir" (X86_EFLAGS_ID)); + if ( ((f1^f2) & X86_EFLAGS_ID) == 0 ) { + g_cpuid_ext_feat_info = 0; + return; + } + + g_cpuid_ext_feat_info = cpuid_ecx(1); + + rdmsrl(IA32_FEATURE_CONTROL_MSR, g_feat_ctrl_msr); +} + +static bool supports_vmx(void) +{ + /* check that processor supports VMX instructions */ + if ( !(g_cpuid_ext_feat_info & X86_FEATURE_VMXE) ) { + printk("ERR: CPU does not support VMX\n"); + return false; + } + printk("CPU is VMX-capable\n"); + + /* and that VMX is enabled in the feature control MSR */ + if ( !(g_feat_ctrl_msr & IA32_FEATURE_CONTROL_MSR_ENABLE_VMX_IN_SMX) ) { + printk("ERR: VMXON disabled by feature control MSR (%lx)\n", + g_feat_ctrl_msr); + return false; + } + + return true; +} + +static bool supports_smx(void) +{ + /* check that processor supports SMX instructions */ + if ( !(g_cpuid_ext_feat_info & X86_FEATURE_SMXE) ) { + printk("ERR: CPU does not support SMX\n"); + return false; + } + printk("CPU is SMX-capable\n"); + + /* + * and that SMX is enabled in the feature control MSR + */ + + /* check that the MSR is locked -- BIOS should always lock it */ + if ( !(g_feat_ctrl_msr & IA32_FEATURE_CONTROL_MSR_LOCK) ) { + printk("ERR: IA32_FEATURE_CONTROL_MSR_LOCK is not locked\n"); + /* in general this should not happen, as BIOS is required to lock */ + /* the MSR; but it may be desirable to allow it sometimes */ +#ifdef PERMISSIVE_BOOT + /* we enable VMX outside of SMX as well so that if there was some */ + /* error in the TXT boot, VMX will continue to work */ + g_feat_ctrl_msr |= 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; + wrmsrl(IA32_FEATURE_CONTROL_MSR, g_feat_ctrl_msr); + return true; +#else + return false; +#endif + } + + /* check that SENTER (w/ full params) is enabled */ + if ( !(g_feat_ctrl_msr & (IA32_FEATURE_CONTROL_MSR_ENABLE_SENTER | + IA32_FEATURE_CONTROL_MSR_SENTER_PARAM_CTL)) ) { + printk("ERR: SENTER disabled by feature control MSR (%lx)\n", + g_feat_ctrl_msr); + return false; + } + + return true; +} + +static bool supports_txt(void) +{ + capabilities_t cap; + + /* processor must support SMX */ + if ( !supports_smx() || !supports_vmx() ) + return false; + + /* testing for chipset support requires enabling SMX on the processor */ + write_cr4(read_cr4() | X86_CR4_SMXE); + printk("SMX is enabled\n"); + + /* + * verify that an TXT-capable chipset is present and + * check that all needed SMX capabilities are supported + */ + + cap = __getsec_capabilities(0); + if ( cap.chipset_present ) { + if ( cap.senter && cap.sexit && cap.parameters && cap.smctrl && + cap.wakeup ) { + printk("TXT chipset and all needed capabilities present\n"); + return true; + } + else + printk("ERR: insufficient SMX capabilities (%x)\n", cap._raw); + } + else + printk("ERR: TXT-capable chipset not present\n"); + + /* since we are failing, we should clear the SMX flag */ + write_cr4(read_cr4() & ~X86_CR4_SMXE); + + return false; +} + +static void print_bios_os_data(bios_os_data_t *bios_os_data) +{ + printk("bios_os_data:\n"); + printk("\t version=%x\n", bios_os_data->version); + printk("\t bios_sinit_size=%x\n", bios_os_data->bios_sinit_size); +} + +static bool verify_bios_os_data(txt_heap_t *txt_heap) +{ + uint64_t size, heap_size; + bios_os_data_t *bios_os_data; + + /* check size */ + heap_size = read_priv_config_reg(TXTCR_HEAP_SIZE); + size = get_bios_os_data_size(txt_heap); + if ( size == 0 ) { + printk("BIOS to OS data size is 0\n"); + return false; + } + if ( size > heap_size ) { + printk("BIOS to OS data size is larger than heap size " + "(%Lx, heap size=%Lx)\n", size, heap_size); + return false; + } + /* TBD: if we add more versions then this will need to change */ + if ( size < sizeof(bios_os_data_t) ) { + printk("BIOS to OS data size (%Lx) is smaller than " + "bios_os_data_t size (%x)\n", size, sizeof(bios_os_data_t)); + return false; + } + + bios_os_data = get_bios_os_data_start(txt_heap); + + /* check version */ + /* we assume backwards compatibility but print a warning */ + if ( bios_os_data->version > 0x01 ) + printk("unsupported BIOS to OS data version (%x)\n", + bios_os_data->version); + + /* no field checks (bios_sinit_size field can be 0) */ + + print_bios_os_data(bios_os_data); + + return true; +} + +static void print_os_mle_data(os_mle_data_t *os_mle_data) +{ + printk("os_mle_data:\n"); + printk("\t version=%x\n", os_mle_data->version); + /* TBD: perhaps eventually print saved_mtrr_state field */ + printk("\t mbi=%p\n", os_mle_data->mbi); +} + +static bool verify_os_mle_data(txt_heap_t *txt_heap) +{ + uint64_t size, heap_size; + os_mle_data_t *os_mle_data; + + /* check size */ + heap_size = read_priv_config_reg(TXTCR_HEAP_SIZE); + size = get_os_mle_data_size(txt_heap); + if ( size == 0 ) { + printk("OS to MLE data size is 0\n"); + return false; + } + if ( size > heap_size ) { + printk("OS to MLE data size is larger than heap size " + "(%Lx, heap size=%Lx)\n", size, heap_size); + return false; + } + if ( size < sizeof(os_mle_data_t) ) { + printk("OS to MLE data size (%Lx) is smaller than " + "os_mle_data_t size (%x)\n", size, sizeof(os_mle_data_t)); + return false; + } + + os_mle_data = get_os_mle_data_start(txt_heap); + + /* check version */ + /* since this data is from our pre-launch to post-launch code only, it */ + /* should always be this */ + if ( os_mle_data->version != 0x01 ) { + printk("unsupported OS to MLE data version (%x)\n", + os_mle_data->version); + return false; + } + + /* field checks */ + if ( os_mle_data->mbi == NULL ) { + printk("OS to MLE data mbi field is NULL\n"); + return false; + } + + print_os_mle_data(os_mle_data); + + return true; +} + +void print_os_sinit_data(os_sinit_data_t *os_sinit_data) +{ + printk("os_sinit_data:\n"); + printk("\t version=%x\n", os_sinit_data->version); + printk("\t mle_ptab=%Lx\n", os_sinit_data->mle_ptab); + printk("\t mle_size=%Lx\n", os_sinit_data->mle_size); + printk("\t mle_hdr_base=%Lx\n", os_sinit_data->mle_hdr_base); +} + +static bool verify_os_sinit_data(txt_heap_t *txt_heap) +{ + uint64_t size, heap_size; + os_sinit_data_t *os_sinit_data; + + /* check size */ + heap_size = read_priv_config_reg(TXTCR_HEAP_SIZE); + size = get_os_sinit_data_size(txt_heap); + if ( size == 0 ) { + printk("OS to SINIT data size is 0\n"); + return false; + } + if ( size > heap_size ) { + printk("OS to SINIT data size is larger than heap size " + "(%Lx, heap size=%Lx)\n", size, heap_size); + return false; + } + + os_sinit_data = get_os_sinit_data_start(txt_heap); + + /* check version */ + if ( os_sinit_data->version > 0x03 ) { + printk("unsupported OS to SINIT data version (%x)\n", + os_sinit_data->version); + return false; + } + + /* if it is version 0x01 then none of the fields get used post-launch */ + /* so no need to verify them (SINIT will have done that) */ + + print_os_sinit_data(os_sinit_data); + + return true; +} + +static void print_sinit_mdrs(sinit_mdr_t mdrs[], uint32_t num_mdrs) +{ + int i; + static char *mem_types[] = {"GOOD", "SMRAM OVERLAY", "SMRAM NON-OVERLAY", + "PCIE EXTENDED CONFIG", "PROTECTED"}; + + printk("\t sinit_mdrs:\n"); + for ( i = 0; i < num_mdrs; i++ ) { + printk("\t\t %016Lx - %016Lx ", mdrs[i].base, + mdrs[i].base + mdrs[i].length); + if ( mdrs[i].mem_type < sizeof(mem_types)/sizeof(mem_types[0]) ) + printk("(%s)\n", mem_types[mdrs[i].mem_type]); + else + printk("(%d)\n", (int)mdrs[i].mem_type); + } +} + +static void print_sinit_mle_data(sinit_mle_data_t *sinit_mle_data) +{ + printk("sinit_mle_data:\n"); + printk("\t version=%x\n", sinit_mle_data->version); + if ( sinit_mle_data->version == 0x01 ) + print_sinit_mdrs(sinit_mle_data->v1.mdrs, sinit_mle_data->v1.num_mdrs); +} + +static bool verify_sinit_mle_data(txt_heap_t *txt_heap) +{ + uint64_t size, heap_size; + sinit_mle_data_t *sinit_mle_data; + + /* check size */ + heap_size = read_priv_config_reg(TXTCR_HEAP_SIZE); + size = get_sinit_mle_data_size(txt_heap); + if ( size == 0 ) { + printk("SINIT to MLE data size is 0\n"); + return false; + } + if ( size > heap_size ) { + printk("SINIT to MLE data size is larger than heap size\n" + "(%Lx, heap size=%Lx)\n", size, heap_size); + /* TBD: un-comment this when have fixed SINIT + return false; */ + } + + sinit_mle_data = get_sinit_mle_data_start(txt_heap); + + /* check version */ + sinit_mle_data = get_sinit_mle_data_start(txt_heap); + if ( sinit_mle_data->version > 0x01 ) + { + printk("unsupported SINIT to MLE data version (%x)\n", + sinit_mle_data->version); + return false; + } + + /* this data is generated by SINIT and so is implicitly trustworthy, */ + /* so we don't need to validate it's fields */ + + print_sinit_mle_data(sinit_mle_data); + + return true; +} + +bool verify_txt_heap(txt_heap_t *txt_heap, bool bios_os_data_only) +{ + uint64_t size1, size2, size3, size4; + + /* verify BIOS to OS data */ + if ( !verify_bios_os_data(txt_heap) ) + return false; + + if ( bios_os_data_only ) + return true; + + /* check that total size is within the heap */ + size1 = get_bios_os_data_size(txt_heap); + size2 = get_os_mle_data_size(txt_heap); + size3 = get_os_sinit_data_size(txt_heap); + size4 = get_sinit_mle_data_size(txt_heap); + if ( (size1 + size2 + size3 + size4) > + read_priv_config_reg(TXTCR_HEAP_SIZE) ) { + printk("TXT heap data sizes (%Lx, %Lx, %Lx, %Lx) are larger than\n" + "heap total size (%Lx)\n", size1, size2, size3, size4, + read_priv_config_reg(TXTCR_HEAP_SIZE)); + /* TBD: un-comment this when have fixed SINIT + return false; */ + } + + /* verify OS to MLE data */ + if ( !verify_os_mle_data(txt_heap) ) + return false; + + /* verify OS to SINIT data */ + if ( !verify_os_sinit_data(txt_heap) ) + return false; + + /* verify SINIT to MLE data */ + if ( !verify_sinit_mle_data(txt_heap) ) + return false; + + return true; +} + +bool txt_verify_platform(void) +{ + txt_heap_t *txt_heap; + bios_os_data_t *bios_os_data; + + read_processor_info(); + + /* support Intel(r) TXT (this includes TPM support) */ + if ( !supports_txt() ) + return false; + + /* check that we support the BIOS to OS data version */ + txt_heap = get_txt_heap(); + bios_os_data = get_bios_os_data_start(txt_heap); + if ( bios_os_data->version > 0x01 ) { + printk("BIOS to OS data version incompatible (%x)\n", + bios_os_data->version); + return false; + } + + return true; +} + +bool txt_post_launch_verify_platform(void) +{ + txt_heap_t *txt_heap; + + /* + * verify some of the heap structures + */ + txt_heap = get_txt_heap(); + + if ( !verify_txt_heap(txt_heap, false) ) + return false; + + /* TBD: verify the saved MTRRs */ + + /* TBD: verify the e820 table against the SINIT MDRs */ + + return true; +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r 419625d61514 -r de5826b5b302 sboot/txt/vmcs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sboot/txt/vmcs.c Fri Jun 08 16:57:19 2007 -0700 @@ -0,0 +1,622 @@ +/* + * vmcs.c: create and manage mini-VT VM for APs to handle INIT-SIPI-SIPI + * + * Copyright (c) 2003-2007, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* no vmexit on external intr as mini guest only handle INIT & SIPI */ +#define MONITOR_PIN_BASED_EXEC_CONTROLS \ + (PIN_BASED_NMI_EXITING) + +#define MONITOR_CPU_BASED_EXEC_CONTROLS_SUBARCH 0 + +#define MONITOR_VM_EXIT_CONTROLS_SUBARCH 0 + +/* no vmexit on hlt as guest only run this instruction */ +#define MONITOR_CPU_BASED_EXEC_CONTROLS \ + ( MONITOR_CPU_BASED_EXEC_CONTROLS_SUBARCH | \ + CPU_BASED_INVDPG_EXITING | \ + CPU_BASED_MWAIT_EXITING ) + +#define MONITOR_VM_EXIT_CONTROLS \ + ( MONITOR_VM_EXIT_CONTROLS_SUBARCH | \ + VM_EXIT_ACK_INTR_ON_EXIT ) + +/* Basic flags for VM-Entry controls. */ +#define MONITOR_VM_ENTRY_CONTROLS 0x00000000 + +#define GUEST_SEGMENT_LIMIT 0xffffffff +#define EXCEPTION_BITMAP_BP (1 << 3) /* Breakpoint */ +#define EXCEPTION_BITMAP_PG (1 << 14) /* Page Fault */ +#define MONITOR_DEFAULT_EXCEPTION_BITMAP \ + ( EXCEPTION_BITMAP_PG | \ + EXCEPTION_BITMAP_BP ) + +#define load_TR(n) __asm__ __volatile__ ("ltr %%ax" : : "a" ((n)<<3) ) + +DEFINE_SPINLOCK(ap_init_lock); + +/* Dynamic (run-time adjusted) execution control flags. */ +static uint32_t vmx_pin_based_exec_control; +static uint32_t vmx_cpu_based_exec_control; +static uint32_t vmx_vmexit_control; +static uint32_t vmx_vmentry_control; + +static uint32_t vmcs_revision_id; + +extern void print_cr0(const char *s); + +static uint32_t adjust_vmx_controls(uint32_t ctrls, uint32_t msr) +{ + uint32_t vmx_msr_low, vmx_msr_high; + + rdmsr(msr, vmx_msr_low, vmx_msr_high); + + /* TBD: need to handle this error */ + /* Bit == 0 means must be zero. */ + BUG_ON(ctrls & ~vmx_msr_high); + + /* Bit == 1 means must be one. */ + ctrls |= vmx_msr_low; + + return ctrls; +} + +static void vmx_init_vmcs_config(void) +{ + uint32_t vmx_msr_low, vmx_msr_high; + uint32_t _vmx_pin_based_exec_control; + uint32_t _vmx_cpu_based_exec_control; + uint32_t _vmx_vmexit_control; + uint32_t _vmx_vmentry_control; + static int vmcs_config_init = 0; + + _vmx_pin_based_exec_control = + adjust_vmx_controls(MONITOR_PIN_BASED_EXEC_CONTROLS, + MSR_IA32_VMX_PINBASED_CTLS_MSR); + _vmx_cpu_based_exec_control = + adjust_vmx_controls(MONITOR_CPU_BASED_EXEC_CONTROLS, + MSR_IA32_VMX_PROCBASED_CTLS_MSR); + _vmx_vmexit_control = + adjust_vmx_controls(MONITOR_VM_EXIT_CONTROLS, + MSR_IA32_VMX_EXIT_CTLS_MSR); + _vmx_vmentry_control = + adjust_vmx_controls(MONITOR_VM_ENTRY_CONTROLS, + MSR_IA32_VMX_ENTRY_CTLS_MSR); + + rdmsr(MSR_IA32_VMX_BASIC_MSR, vmx_msr_low, vmx_msr_high); + + if ( vmcs_config_init == 0 ) { + vmcs_revision_id = vmx_msr_low; + vmx_pin_based_exec_control = _vmx_pin_based_exec_control; + vmx_cpu_based_exec_control = _vmx_cpu_based_exec_control; + vmx_vmexit_control = _vmx_vmexit_control; + vmx_vmentry_control = _vmx_vmentry_control; + vmcs_config_init = 1; + } + else if ( (vmcs_revision_id != vmx_msr_low) || + (vmx_pin_based_exec_control != _vmx_pin_based_exec_control) || + (vmx_cpu_based_exec_control != _vmx_cpu_based_exec_control) || + (vmx_vmexit_control != _vmx_vmexit_control) || + (vmx_vmentry_control != _vmx_vmentry_control) ) + printk("vmx_init_config different on different AP.\n"); + + /* TBD: handle this as an error */ + /* IA-32 SDM Vol 3B: VMCS size is never greater than 4kB. */ + if ( (vmx_msr_high & 0x1fff) > PAGE_SIZE ) + printk("vmcs size wrong.\n"); +} + +extern uint32_t idle_pg_table[PAGE_SIZE / 4]; +extern char vmcs_end[]; /* end of vmcs region */ + +/* build a 1-level identity-map page table on AP for vmxon*/ +static void build_ap_pagetable(void) +{ + uint32_t pt_entry = 0xe3; /* PRESENT+RW+A+D+4MB */ + uint32_t *pte = &idle_pg_table[0]; + uint32_t sboot_end = (uint32_t)&vmcs_end; + while ( pt_entry <= sboot_end + 0xe3 ) { + *pte = pt_entry; + pt_entry += ( 1 << L2_PAGETABLE_SHIFT ); + pte++; + } + printk("build 4M page table %p.\n", idle_pg_table); +} + +extern char host_vmcs[PAGE_SIZE]; +extern char ap_vmcs[PAGE_SIZE]; + +static bool start_vmx(void) +{ + uint32_t eax, edx; + struct vmcs_struct *vmcs; + + vmcs = (struct vmcs_struct*)host_vmcs; + memset(vmcs, 0, PAGE_SIZE); + + set_in_cr4(X86_CR4_VMXE); + + vmx_init_vmcs_config(); + vmcs->vmcs_revision_id = vmcs_revision_id; + + rdmsr(MSR_EFER, eax, edx); + + /* enable paging as required by vmentry */ + build_ap_pagetable(); + write_cr3((unsigned long)idle_pg_table); + set_in_cr4(X86_CR4_PSE); + write_cr0(read_cr0() | X86_CR0_PG); + + if ( __vmxon((unsigned long)vmcs) ) { + clear_in_cr4(X86_CR4_VMXE); + clear_in_cr4(X86_CR4_PSE); + write_cr0(read_cr0() & ~X86_CR0_PG); + printk("VMXON failed\n"); + return false; + } + + printk("VMXON done.\n"); + return true; +} + +static void stop_vmx(void) +{ + if ( !(read_cr4() & X86_CR4_VMXE) ) + return; + + __vmpclear((unsigned long)ap_vmcs); + __vmxoff(); + + clear_in_cr4(X86_CR4_VMXE); + + /* diable paging to restore AP's state to boot xen */ + write_cr0(read_cr0() & ~X86_CR0_PG); + clear_in_cr4(X86_CR4_PSE); +} + +/* Dump a section of VMCS */ +static void print_section(const char *header, uint32_t start, uint32_t end, + int incr) +{ + uint32_t addr, j; + unsigned long val; + int code, rc; + static char *fmt[4] = {"0x%04lx ", "0x%016lx ", "0x%08lx ", "0x%016lx "}; + static char *err[4] = {"------ ", "------------------ ", "---------- ", + "------------------ "}; + + /* Find width of the field (encoded in bits 14:13 of address) */ + code = (start >> 13) & 3; + + if ( header ) + printk("\t %s", header); + + for ( addr = start, j = 0; addr <= end; addr += incr, j++ ) { + if ( !(j & 3) ) + printk("\n\t 0x%08x: ", addr); + + val = __vmread_safe(addr, &rc); + if ( rc == 0 ) + printk(fmt[code], val); + else + printk("%s", err[code]); + } + + printk("\n"); +} + +/* Dump current VMCS */ +static void vmcs_dump_vcpu(void) +{ + print_section("16-bit Guest-State Fields", 0x800, 0x80e, 2); + print_section("16-bit Host-State Fields", 0xc00, 0xc0c, 2); + print_section("64-bit Control Fields", 0x2000, 0x2013, 1); + print_section("64-bit Guest-State Fields", 0x2800, 0x2803, 1); + print_section("32-bit Control Fields", 0x4000, 0x401c, 2); + print_section("32-bit RO Data Fields", 0x4400, 0x440e, 2); + print_section("32-bit Guest-State Fields", 0x4800, 0x482a, 2); + print_section("32-bit Host-State Fields", 0x4c00, 0x4c00, 2); + print_section("Natural 64-bit Control Fields", 0x6000, 0x600e, 2); + print_section("64-bit RO Data Fields", 0x6400, 0x640A, 2); + print_section("Natural 64-bit Guest-State Fields", 0x6800, 0x6826, 2); + print_section("Natural 64-bit Host-State Fields", 0x6c00, 0x6c16, 2); +} + +/* in sboot/common/boot.S */ +extern void vmx_asm_vmexit_handler(void); +extern void _mini_guest(void); + +/* consturct guest/host vmcs: + * make guest vmcs from physical environment, + * so only one binary switch between root and non-root + */ +static void construct_vmcs(void) +{ + struct { + uint16_t limit; + uint32_t base; + } __attribute__ ((packed)) xdt; + unsigned long cr0, cr3, cr4, eflags, rsp; + unsigned int tr; + union vmcs_arbytes arbytes; + uint16_t seg; + + __vmwrite(PIN_BASED_VM_EXEC_CONTROL, vmx_pin_based_exec_control); + __vmwrite(VM_EXIT_CONTROLS, vmx_vmexit_control); + __vmwrite(VM_ENTRY_CONTROLS, vmx_vmentry_control); + __vmwrite(CPU_BASED_VM_EXEC_CONTROL, vmx_cpu_based_exec_control); + + /* segments selectors. */ + __asm__ __volatile__ ("movl %%ss, %0\n" : "=r"(seg)); + __vmwrite(HOST_SS_SELECTOR, seg); + __vmwrite(GUEST_SS_SELECTOR, seg); + + __asm__ __volatile__ ("movl %%ds, %0\n" : "=r"(seg)); + __vmwrite(HOST_DS_SELECTOR, seg); + __vmwrite(GUEST_DS_SELECTOR, seg); + + __asm__ __volatile__ ("movl %%es, %0\n" : "=r"(seg)); + __vmwrite(HOST_ES_SELECTOR, seg); + __vmwrite(GUEST_ES_SELECTOR, seg); + + __asm__ __volatile__ ("movl %%fs, %0\n" : "=r"(seg)); + __vmwrite(HOST_FS_SELECTOR, seg); + __vmwrite(GUEST_FS_SELECTOR, seg); + + __asm__ __volatile__ ("movl %%gs, %0\n" : "=r"(seg)); + __vmwrite(HOST_GS_SELECTOR, seg); + __vmwrite(GUEST_GS_SELECTOR, seg); + + __asm__ __volatile__ ("movl %%cs, %0\n" : "=r"(seg)); + __vmwrite(GUEST_CS_SELECTOR, seg); + __vmwrite(GUEST_RIP, (uint32_t)&_mini_guest); + + __vmwrite(HOST_CS_SELECTOR, seg); + __vmwrite(HOST_RIP, (unsigned long)vmx_asm_vmexit_handler); + + /* segment limits */ + __vmwrite(GUEST_ES_LIMIT, GUEST_SEGMENT_LIMIT); + __vmwrite(GUEST_SS_LIMIT, GUEST_SEGMENT_LIMIT); + __vmwrite(GUEST_DS_LIMIT, GUEST_SEGMENT_LIMIT); + __vmwrite(GUEST_FS_LIMIT, GUEST_SEGMENT_LIMIT); + __vmwrite(GUEST_GS_LIMIT, GUEST_SEGMENT_LIMIT); + __vmwrite(GUEST_CS_LIMIT, GUEST_SEGMENT_LIMIT); + + /* segment AR bytes, see boot.S for details */ + arbytes.bytes = 0; + arbytes.fields.seg_type = 0x3; /* type = 3 */ + arbytes.fields.s = 1; /* code or data, i.e. not system */ + arbytes.fields.dpl = 0; /* DPL = 0 */ + arbytes.fields.p = 1; /* segment present */ + arbytes.fields.default_ops_size = 1; /* 32-bit */ + arbytes.fields.g = 1; + + arbytes.fields.null_bit = 0; /* not null */ + __vmwrite(GUEST_ES_AR_BYTES, arbytes.bytes); + __vmwrite(GUEST_SS_AR_BYTES, arbytes.bytes); + __vmwrite(GUEST_DS_AR_BYTES, arbytes.bytes); + __vmwrite(GUEST_FS_AR_BYTES, arbytes.bytes); + __vmwrite(GUEST_GS_AR_BYTES, arbytes.bytes); + + arbytes.fields.seg_type = 0xb; /* type = 0xb */ + __vmwrite(GUEST_CS_AR_BYTES, arbytes.bytes); + + /* segment BASE */ + __vmwrite(GUEST_ES_BASE, 0); + __vmwrite(GUEST_SS_BASE, 0); + __vmwrite(GUEST_DS_BASE, 0); + __vmwrite(GUEST_FS_BASE, 0); + __vmwrite(GUEST_GS_BASE, 0); + __vmwrite(GUEST_CS_BASE, 0); + + __vmwrite(HOST_FS_BASE, 0); + __vmwrite(HOST_GS_BASE, 0); + + /* Guest LDT and TSS */ + __vmwrite(GUEST_LDTR_SELECTOR, 0); + __vmwrite(GUEST_LDTR_BASE, 0); + __vmwrite(GUEST_LDTR_LIMIT, 0xffff); + + __asm__ __volatile__ ("str (%0) \n" :: "a"(&tr) : "memory"); + if ( tr == 0 ) + printk("tr is 0 on ap, may vmlaunch fail.\n"); + __vmwrite(GUEST_TR_SELECTOR, tr); + __vmwrite(GUEST_TR_BASE, 0); + __vmwrite(GUEST_TR_LIMIT, 0xffff); + + __vmwrite(HOST_TR_SELECTOR, tr); + __vmwrite(HOST_TR_BASE, 0); + + + /* sboot do not use ldt */ + arbytes.bytes = 0; + arbytes.fields.s = 0; /* not code or data segement */ + arbytes.fields.seg_type = 0x2; /* LTD */ + arbytes.fields.p = 1; /* segment present */ + arbytes.fields.default_ops_size = 0; /* 16-bit */ + arbytes.fields.g = 1; + __vmwrite(GUEST_LDTR_AR_BYTES, arbytes.bytes); + + /* setup a TSS for vmentry as zero TR is not allowed */ + arbytes.bytes = 0; + arbytes.fields.s = 0; /* not code or data seg */ + arbytes.fields.seg_type = 0xb; /* 32-bit TSS (busy) */ + arbytes.fields.p = 1; /* segment present */ + arbytes.fields.default_ops_size = 0; /* 16-bit */ + arbytes.fields.g = 1; + __vmwrite(GUEST_TR_AR_BYTES, arbytes.bytes); + + /* GDT */ + __asm__ __volatile__ ("sgdt (%0) \n" :: "a"(&xdt) : "memory"); + __vmwrite(GUEST_GDTR_BASE, xdt.base); + __vmwrite(GUEST_GDTR_LIMIT, xdt.limit); + + __vmwrite(HOST_GDTR_BASE, xdt.base); + + /* IDT */ + __asm__ __volatile__ ("sidt (%0) \n" :: "a"(&xdt) : "memory"); + printk("idt.base=0x%x, limit=0x%x.\n", xdt.base, xdt.limit); + /* TBD: sboot's idt base is not cannonical, so use 0 */ + __vmwrite(GUEST_IDTR_BASE, 0); + __vmwrite(GUEST_IDTR_LIMIT, xdt.limit); + + __vmwrite(HOST_IDTR_BASE, xdt.base); + + /* control registers. */ + cr0 = read_cr0(); + cr3 = read_cr3(); + cr4 = read_cr4(); + __vmwrite(HOST_CR0, cr0); + __vmwrite(HOST_CR4, cr4); + __vmwrite(HOST_CR3, cr3); + + __vmwrite(GUEST_CR0, cr0); + __vmwrite(CR0_READ_SHADOW, cr0); + __vmwrite(GUEST_CR4, cr4); + __vmwrite(CR4_READ_SHADOW, cr4); + __vmwrite(GUEST_CR3, cr3); + + /* debug register */ + __vmwrite(GUEST_DR7, 0); + + /* rflags & rsp */ + __save_flags(eflags); + __vmwrite(GUEST_RFLAGS, eflags); + + __asm__ __volatile__ ("mov %%esp,%0\n\t" :"=r" (rsp)); + __vmwrite(GUEST_RSP, rsp); + __vmwrite(HOST_RSP, rsp); + + /* MSR intercepts. */ + __vmwrite(VM_EXIT_MSR_LOAD_ADDR, 0); + __vmwrite(VM_EXIT_MSR_STORE_ADDR, 0); + __vmwrite(VM_EXIT_MSR_STORE_COUNT, 0); + __vmwrite(VM_EXIT_MSR_LOAD_COUNT, 0); + __vmwrite(VM_ENTRY_MSR_LOAD_COUNT, 0); + + __vmwrite(VM_ENTRY_INTR_INFO_FIELD, 0); + + __vmwrite(CR0_GUEST_HOST_MASK, ~0UL); + __vmwrite(CR4_GUEST_HOST_MASK, ~0UL); + + __vmwrite(PAGE_FAULT_ERROR_CODE_MASK, 0); + __vmwrite(PAGE_FAULT_ERROR_CODE_MATCH, 0); + + __vmwrite(CR3_TARGET_COUNT, 0); + + /* guest need do nothing but vmexit when INIT-SIPI-SIPI */ + __vmwrite(GUEST_ACTIVITY_STATE, GUEST_STATE_HALT); + + __vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0); + __vmwrite(VMCS_LINK_POINTER, ~0UL); + + __vmwrite(VMCS_LINK_POINTER_HIGH, ~0UL); + + __vmwrite(EXCEPTION_BITMAP, MONITOR_DEFAULT_EXCEPTION_BITMAP); + + printk("vmcs setup done.\n"); +} + +static void vmx_create_vmcs(void) +{ + struct vmcs_struct *vmcs = (struct vmcs_struct*)ap_vmcs; + + memset(vmcs, 0, PAGE_SIZE); + + vmcs->vmcs_revision_id = vmcs_revision_id; + + /* vir addr equal to phy addr as we setup identity page table */ + __vmpclear((unsigned long)vmcs); + + __vmptrld((unsigned long)vmcs); + + construct_vmcs(); +} + +static void launch_mini_guest(void) +{ + unsigned long error; + + __vmlaunch(); + + /* should not reach here */ + error = __vmread(VM_INSTRUCTION_ERROR); + printk(" error code %lx\n", error); + printk("************* VMCS Area **************\n"); + vmcs_dump_vcpu(); + printk("**************************************\n"); +} + +static void vmx_failed_vmentry(unsigned int exit_reason) +{ + unsigned int failed_vmentry_reason = (uint16_t)exit_reason; + unsigned long exit_qualification; + + exit_qualification = __vmread(EXIT_QUALIFICATION); + printk("Failed vm entry (exit reason 0x%x) ", exit_reason); + switch ( failed_vmentry_reason ) + { + case EXIT_REASON_INVALID_GUEST_STATE: + printk("caused by invalid guest state (%ld).\n", + exit_qualification); + break; + case EXIT_REASON_MSR_LOADING: + printk("caused by MSR entry %ld loading.\n", exit_qualification); + break; + case EXIT_REASON_MACHINE_CHECK: + printk("caused by machine check.\n"); + break; + default: + printk("reason not known yet!"); + break; + } + + printk("************* VMCS Area **************\n"); + vmcs_dump_vcpu(); + printk("**************************************\n"); +} + +/* Vmexit handler for physical INIT-SIPI-SIPI from the BSP + * Do not use printk in this critical path as BSP only + * wait for a short time + */ +void vmx_vmexit_handler(void) +{ + unsigned long error; + unsigned int exit_reason, apicid; + static int state = AP_WAIT_INIT; + + exit_reason = __vmread(VM_EXIT_REASON); +/* printk("vmx_vmexit_handler, exit_reason=%x.\n", exit_reason);*/ + + if ( (exit_reason & VMX_EXIT_REASONS_FAILED_VMENTRY) ) { + printk("failed vmentry.\n"); + vmx_failed_vmentry(exit_reason); + goto out; + } + + switch ( exit_reason ) + { + case EXIT_REASON_INIT: + if ( state == AP_WAIT_INIT ) { + state = AP_WAIT_SIPI1; + __vmwrite(GUEST_ACTIVITY_STATE, GUEST_STATE_WAIT_SIPI); + } + break; + case EXIT_REASON_SIPI: + if ( state == AP_WAIT_SIPI1 ) { + state = AP_WAIT_SIPI2; + __vmwrite(GUEST_ACTIVITY_STATE, GUEST_STATE_WAIT_SIPI); + } + else if ( state == AP_WAIT_SIPI2 ) + state = AP_WAIT_DONE; + break; + default: + printk("can't handle vmexit due to 0x%x.\n", exit_reason); + } + + if ( state == AP_WAIT_DONE ) { /* disable VT then jump to xen code */ +/* printk("sucessfully handle INIT-SIPI-SIPI on AP.\n");*/ + stop_vmx(); + state = AP_WAIT_INIT; + spin_unlock(&ap_init_lock); + apicid = cpuid_ebx(1) >> 24; + cpu_wakeup(apicid); + return; + } + + /* resume mini guest to handle following signal */ + __vmresume(); + + /* should not reach here */ + error = __vmread(VM_INSTRUCTION_ERROR); + printk(" error code %lx\n", error); + +out: + printk("************* VMCS Area **************\n"); + vmcs_dump_vcpu(); + printk("**************************************\n"); + + spin_unlock(&ap_init_lock); +} + +/* Launch a mini guest to handle the physical INIT-SIPI-SIPI from BSP */ +void handle_init_sipi_sipi(void) +{ + /* setup a dummy tss as vmentry require a non-zero host TR */ + load_TR(3); + + /* handle APs one by one by a big spinlock, */ + spin_lock(&ap_init_lock); + + /* prepare a guest for INIT-SIPI-SIPI handling */ + /* 1: setup VMX environment and VMXON */ + if ( !start_vmx() ) + goto out; + + /* 2: setup VMCS */ + vmx_create_vmcs(); + + /* 3: launch VM */ + launch_mini_guest(); + +out: + spin_unlock(&ap_init_lock); +} + + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */