From: Gang W. <gan...@in...> - 2012-12-25 04:20:57
|
changeset 4ab4774b0593 in /hgroot/tboot/tboot details: http://tboot.hg.sourceforge.net:8000/hgroot/tboot/tboot?cmd=changeset;node=4ab4774b0593 description: Add a new option "call_racm=true|false" for revocation acm(RACM) launch RACM is a acm similar as bios acm, which provides function to revoke old buggy SINIT version, and needs to be launched with getsec[ENTERACCS] instruction. RACM need to be provided in the same way as SINIT: add a module line after tboot line in grub file. Below is a example GRUB entry for RACM launch: title RACM Launch root (hd0,1) kernel /tboot.gz logging=serial,vga,memory call_racm=true module /racm.bin Tboot will always warm reset platform after RACM was launched & executed. Whether RACM launch has succeeded or not could be checked via doing a normal tboot launch right after the warm reset and looking into the TXT.ERRORCODE value output by the normal tboot launch. Signed-off-by: Gang Wei <gan...@in...> diffstat: tboot/common/cmdline.c | 19 +++++-- tboot/common/tboot.c | 50 ++++++++++++++++++++ tboot/include/cmdline.h | 1 + tboot/include/txt/acmod.h | 3 + tboot/include/txt/smx.h | 13 +++++ tboot/include/txt/txt.h | 1 + tboot/txt/acmod.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++ tboot/txt/txt.c | 79 +++++++++++++++++++++++++++++++ 8 files changed, 276 insertions(+), 5 deletions(-) diffs (truncated from 417 to 300 lines): diff -r f37e84b33130 -r 4ab4774b0593 tboot/common/cmdline.c --- a/tboot/common/cmdline.c Tue Dec 25 09:42:31 2012 +0800 +++ b/tboot/common/cmdline.c Tue Dec 25 10:44:16 2012 +0800 @@ -74,6 +74,7 @@ { "ap_wake_mwait", "false" }, /* true|false */ { "pcr_map", "legacy" }, /* legacy|da */ { "min_ram", "0" }, /* size in bytes | 0 for no min */ + { "call_racm", "false" }, /* true|false */ { NULL, NULL } }; static char g_tboot_param_values[ARRAY_SIZE(g_tboot_cmdline_options)][MAX_VALUE_LEN]; @@ -455,11 +456,6 @@ g_min_ram = strtoul(min_ram, NULL, 0); } - -/* - * linux kernel command line parsing - */ - bool get_tboot_mwait(void) { const char *mwait = get_option_val(g_tboot_cmdline_options, @@ -469,6 +465,19 @@ return true; } +bool get_tboot_call_racm(void) +{ + const char *call_racm = get_option_val(g_tboot_cmdline_options, + g_tboot_param_values, "call_racm"); + if ( call_racm == NULL || strcmp(call_racm, "false") == 0 ) + return false; + return true; +} + +/* + * linux kernel command line parsing + */ + bool get_linux_vga(int *vid_mode) { const char *vga = get_option_val(g_linux_cmdline_options, diff -r f37e84b33130 -r 4ab4774b0593 tboot/common/tboot.c --- a/tboot/common/tboot.c Tue Dec 25 09:42:31 2012 +0800 +++ b/tboot/common/tboot.c Tue Dec 25 10:44:16 2012 +0800 @@ -262,6 +262,52 @@ _prot_to_real(sipi_vec); } +#define ICR_LOW 0x300 + +void startup_rlps(void) +{ + uint32_t rlp_count = ((cpuid_ecx(1) >> 16) & 0xff) - 1; + uint32_t apicbase = (uint32_t)rdmsr(MSR_APICBASE) & 0xfffffffffffff000; + + if ( rlp_count == 0 ) + return; + + /* send init ipi to all rlp -- Dest Shorthand: 11, Delivery Mode: 101 */ + writel(apicbase + ICR_LOW, 0xc0500); +} + +void launch_racm(void) +{ + tb_error_t err; + + /* bsp check & tpm check done by caller */ + /* SMX must be supported */ + if ( !(cpuid_ecx(1) & CPUID_X86_FEATURE_SMX) ) + apply_policy(TB_ERR_SMX_NOT_SUPPORTED); + + /* Enable SMX */ + write_cr4(read_cr4() | CR4_SMXE); + + /* prepare cpu */ + if ( !prepare_cpu() ) + apply_policy(TB_ERR_FATAL); + + /* prepare tpm */ + if ( !prepare_tpm() ) + apply_policy(TB_ERR_TPM_NOT_READY); + + /* Place RLPs in Wait for SIPI state */ + startup_rlps(); + + /* Verify mbi */ + if ( !verify_mbi(g_mbi) ) + apply_policy(TB_ERR_FATAL); + + /* load racm */ + err = txt_launch_racm(g_mbi); + apply_policy(err); +} + void begin_launch(multiboot_info_t *mbi) { tb_error_t err; @@ -323,6 +369,10 @@ err = set_policy(); apply_policy(err); + /* if telled to call revocation acm, go with simplified path */ + if ( get_tboot_call_racm() ) + launch_racm(); /* never return */ + /* need to verify that platform supports TXT before we can check error */ /* (this includes TPM support) */ err = supports_txt(); diff -r f37e84b33130 -r 4ab4774b0593 tboot/include/cmdline.h --- a/tboot/include/cmdline.h Tue Dec 25 09:42:31 2012 +0800 +++ b/tboot/include/cmdline.h Tue Dec 25 10:44:16 2012 +0800 @@ -50,6 +50,7 @@ extern bool get_tboot_mwait(void); extern bool get_tboot_prefer_da(void); extern void get_tboot_min_ram(void); +extern bool get_tboot_call_racm(void); /* for parse cmdline of linux kernel, say vga and mem */ extern void linux_parse_cmdline(const char *cmdline); diff -r f37e84b33130 -r 4ab4774b0593 tboot/include/txt/acmod.h --- a/tboot/include/txt/acmod.h Tue Dec 25 09:42:31 2012 +0800 +++ b/tboot/include/txt/acmod.h Tue Dec 25 10:44:16 2012 +0800 @@ -136,6 +136,9 @@ } acm_processor_id_list_t; extern void print_txt_caps(const char *prefix, txt_caps_t caps); +extern bool is_racm_acmod(const void *acmod_base, uint32_t acmod_size, bool quiet); +extern acm_hdr_t *copy_racm(const acm_hdr_t *racm); +extern bool verify_racm(const acm_hdr_t *acm_hdr); extern bool is_sinit_acmod(const void *acmod_base, uint32_t acmod_size, bool quiet); extern bool does_acmod_match_platform(const acm_hdr_t* hdr); extern acm_hdr_t *copy_sinit(const acm_hdr_t *sinit); diff -r f37e84b33130 -r 4ab4774b0593 tboot/include/txt/smx.h --- a/tboot/include/txt/smx.h Tue Dec 25 09:42:31 2012 +0800 +++ b/tboot/include/txt/smx.h Tue Dec 25 10:44:16 2012 +0800 @@ -45,6 +45,7 @@ /* GETSEC leaf function codes */ #define IA32_GETSEC_CAPABILITIES 0 +#define IA32_GETSEC_ENTERACCS 2 #define IA32_GETSEC_SENTER 4 #define IA32_GETSEC_SEXIT 5 #define IA32_GETSEC_PARAMETERS 6 @@ -144,6 +145,18 @@ if ( pecx != NULL ) *pecx = ecx; } +static inline void __getsec_enteraccs(uint32_t acm_base, uint32_t acm_size, + uint32_t fn) +{ + __asm__ __volatile__ (IA32_GETSEC_OPCODE "\n" + : + : "a"(IA32_GETSEC_ENTERACCS), + "b"(acm_base), + "c"(acm_size), + "D"(0), + "S"(fn)); +} + #endif /* __TXT_SMX_H__ */ diff -r f37e84b33130 -r 4ab4774b0593 tboot/include/txt/txt.h --- a/tboot/include/txt/txt.h Tue Dec 25 09:42:31 2012 +0800 +++ b/tboot/include/txt/txt.h Tue Dec 25 10:44:16 2012 +0800 @@ -44,6 +44,7 @@ extern tb_error_t txt_verify_platform(void); extern bool txt_prepare_cpu(void); extern tb_error_t txt_launch_environment(const multiboot_info_t *mbi); +extern tb_error_t txt_launch_racm(const multiboot_info_t *mbi); extern void txt_post_launch(void); extern tb_error_t txt_protect_mem_regions(void); extern tb_error_t txt_post_launch_verify_platform(void); diff -r f37e84b33130 -r 4ab4774b0593 tboot/txt/acmod.c --- a/tboot/txt/acmod.c Tue Dec 25 09:42:31 2012 +0800 +++ b/tboot/txt/acmod.c Tue Dec 25 10:44:16 2012 +0800 @@ -425,6 +425,26 @@ return true; } +bool is_racm_acmod(const void *acmod_base, uint32_t acmod_size, bool quiet) +{ + uint8_t type; + + if ( !is_acmod(acmod_base, acmod_size, &type, quiet) ) + return false; + + if ( type != ACM_CHIPSET_TYPE_BIOS ) { + printk(TBOOT_ERR"ACM is not an BIOS ACM (%x)\n", type); + return false; + } + + if ( acmod_size != 0x8000 && acmod_size != 0x10000 ) { + printk(TBOOT_ERR"ACM is not an RACM, bad size (0x%x)\n", acmod_size); + return false; + } + + return true; +} + bool is_sinit_acmod(const void *acmod_base, uint32_t acmod_size, bool quiet) { uint8_t type; @@ -561,6 +581,29 @@ return (acm_hdr_t *)sinit_region_base; } +static void *alloc_racm_region(uint32_t size) +{ + /* TODO: find a real unused memory place through mbi */ + return (void *)(long)(0x2000000 + size - size); /* 32M */ +} + +acm_hdr_t *copy_racm(const acm_hdr_t *racm) +{ + /* find a 32KB aligned memory */ + uint32_t racm_region_size = racm->size*4; + void *racm_region_base = alloc_racm_region(racm_region_size); + printk(TBOOT_DETA"RACM.BASE: %p\n", racm_region_base); + printk(TBOOT_DETA"RACM.SIZE: 0x%x (%u)\n", racm_region_size, racm_region_size); + + /* copy it there */ + memcpy(racm_region_base, racm, racm->size*4); + + printk(TBOOT_DETA"copied RACM (size=%x) to %p\n", racm->size*4, + racm_region_base); + + return (acm_hdr_t *)racm_region_base; +} + acm_hdr_t *copy_sinit(const acm_hdr_t *sinit) { /* get BIOS-reserved region from TXT.SINIT.BASE config reg */ @@ -618,6 +661,78 @@ } #endif /* IS_INCLUDED */ +bool verify_racm(const acm_hdr_t *acm_hdr) +{ + getsec_parameters_t params; + uint32_t size; + + /* assumes this already passed is_acmod() test */ + + size = acm_hdr->size * 4; /* hdr size is in dwords, we want bytes */ + + /* + * AC mod must start on 4k page boundary + */ + + if ( (unsigned long)acm_hdr & 0xfff ) { + printk(TBOOT_ERR"AC mod base not 4K aligned (%p)\n", acm_hdr); + return false; + } + printk(TBOOT_INFO"AC mod base alignment OK\n"); + + /* AC mod size must: + * - be multiple of 64 + * - greater than ??? + * - less than max supported size for this processor + */ + + if ( (size == 0) || ((size % 64) != 0) ) { + printk(TBOOT_ERR"AC mod size %x bogus\n", size); + return false; + } + + if ( !get_parameters(¶ms) ) { + printk(TBOOT_ERR"get_parameters() failed\n"); + return false; + } + + if ( size > params.acm_max_size ) { + printk(TBOOT_ERR"AC mod size too large: %x (max=%x)\n", size, + params.acm_max_size); + return false; + } + + printk(TBOOT_INFO"AC mod size OK\n"); + + /* + * perform checks on AC mod structure + */ + + /* print it for debugging */ + print_acm_hdr(acm_hdr, "RACM"); + + /* entry point is offset from base addr so make sure it is within module */ + if ( acm_hdr->entry_point >= size ) { + printk(TBOOT_ERR"AC mod entry (%08x) >= AC mod size (%08x)\n", + acm_hdr->entry_point, size); + return false; + } + + /* overflow? */ + if ( plus_overflow_u32(acm_hdr->seg_sel, 8) ) { + printk(TBOOT_ERR"seg_sel plus 8 overflows\n"); + return false; |