# HG changeset patch # User Joseph Cihula # Date 1233206079 28800 # Node ID c82b6c6847b230f5166fe128cf20eb4c790aae9a # Parent 3fba2cdf7dd5b4fa0d902d7ca6bedda454d97cab Remove the shutdown_entry32 and shutdown_entry64 from tboot_shared_t and have just a single shutdown_entry field. This requires a change to the tboot_shared_t data structure that is not backwards compatible, so the version has been incremented to 3. Since backwards compatbility was broken with the previous patch, this is intended to be used with a set of patches to Xen that support the new tboot_shared_t. Signed-off-by: Joseph Cihula diff -r 3fba2cdf7dd5 -r c82b6c6847b2 include/tboot.h --- a/include/tboot.h Tue Jan 20 22:26:27 2009 -0800 +++ b/include/tboot.h Wed Jan 28 21:14:39 2009 -0800 @@ -2,7 +2,7 @@ * tboot.h: shared data structure with MLE and kernel and functions * used by kernel for runtime support * - * Copyright (c) 2006-2008, Intel Corporation + * Copyright (c) 2006-2009, Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -67,11 +67,11 @@ typedef struct __packed { } tboot_acpi_sleep_info; typedef struct __packed { + /* version 3+ fields: */ uuid_t uuid; /* {663C8DFF-E8B3-4b82-AABF-19EA4D057A08} */ - uint32_t version; /* currently 0.2 */ + uint32_t version; /* currently 0.3 */ uint32_t log_addr; /* physical addr of log or NULL if none */ - uint32_t shutdown_entry32; /* entry point for tboot shutdown from 32b */ - uint32_t shutdown_entry64; /* entry point for tboot shutdown from 64b */ + uint32_t shutdown_entry; /* entry point for tboot shutdown */ uint32_t shutdown_type; /* type of shutdown (TB_SHUTDOWN_*) */ uint32_t s3_tb_wakeup_entry;/* entry point for tboot s3 wake up */ uint32_t s3_k_wakeup_entry; /* entry point for xen s3 wake up */ @@ -120,8 +120,7 @@ static inline void print_tboot_shared(tb printk("tboot_shared data:\n"); printk("\t version: %d\n", tboot_shared->version); printk("\t log_addr: 0x%08x\n", tboot_shared->log_addr); - printk("\t shutdown_entry32: 0x%08x\n", tboot_shared->shutdown_entry32); - printk("\t shutdown_entry64: 0x%08x\n", tboot_shared->shutdown_entry64); + printk("\t shutdown_entry: 0x%08x\n", tboot_shared->shutdown_entry); printk("\t shutdown_type: %d\n", tboot_shared->shutdown_type); printk("\t s3_tb_wakeup_entry: 0x%08x\n", tboot_shared->s3_tb_wakeup_entry); diff -r 3fba2cdf7dd5 -r c82b6c6847b2 tboot/common/tboot.c --- a/tboot/common/tboot.c Tue Jan 20 22:26:27 2009 -0800 +++ b/tboot/common/tboot.c Wed Jan 28 21:14:39 2009 -0800 @@ -2,7 +2,7 @@ * tboot.c: main entry point and "generic" routines for measured launch * support * - * Copyright (c) 2006-2008, Intel Corporation + * Copyright (c) 2006-2009, Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -214,10 +214,9 @@ static void post_launch(void) */ memset(&_tboot_shared, 0, PAGE_SIZE); _tboot_shared.uuid = (uuid_t)TBOOT_SHARED_UUID; - _tboot_shared.version = 0x02; + _tboot_shared.version = 3; _tboot_shared.log_addr = (uint32_t)g_log; - _tboot_shared.shutdown_entry32 = (uint32_t)shutdown_entry; - _tboot_shared.shutdown_entry64 = (uint32_t)shutdown_entry; + _tboot_shared.shutdown_entry = (uint32_t)shutdown_entry; _tboot_shared.s3_tb_wakeup_entry = (uint32_t)TBOOT_S3_WAKEUP_ADDR; _tboot_shared.tboot_base = (uint32_t)&_start; _tboot_shared.tboot_size = (uint32_t)&_end - (uint32_t)&_start; # HG changeset patch # User Joseph Cihula # Date 1233209245 28800 # Node ID a5551650862acc762cbe6649b7332eb74d48b51c # Parent c82b6c6847b230f5166fe128cf20eb4c790aae9a Support ACPI GAS (Generic Address Structure) for handling sleep states. Signed-off-by: Shane Wang Signed-off-by: Joseph Cihula diff -r c82b6c6847b2 -r a5551650862a include/tboot.h --- a/include/tboot.h Wed Jan 28 21:14:39 2009 -0800 +++ b/include/tboot.h Wed Jan 28 22:07:25 2009 -0800 @@ -57,14 +57,26 @@ typedef struct __packed { * used to communicate between tboot and the launched kernel (i.e. Xen) */ +/* GAS - Generic Address Structure (ACPI 2.0+) */ typedef struct __packed { - uint16_t pm1a_cnt; - uint16_t pm1b_cnt; - uint16_t pm1a_evt; - uint16_t pm1b_evt; + uint8_t space_id; + uint8_t bit_width; + uint8_t bit_offset; + uint8_t access_width; + uint64_t address; +} tboot_acpi_generic_address_t; + +typedef struct __packed { + tboot_acpi_generic_address_t pm1a_cnt_blk; + tboot_acpi_generic_address_t pm1b_cnt_blk; + tboot_acpi_generic_address_t pm1a_evt_blk; + tboot_acpi_generic_address_t pm1b_evt_blk; uint16_t pm1a_cnt_val; uint16_t pm1b_cnt_val; -} tboot_acpi_sleep_info; + uint64_t wakeup_vector; + uint32_t vector_width; + uint64_t kernel_s3_resume_vector; +} tboot_acpi_sleep_info_t; typedef struct __packed { /* version 3+ fields: */ @@ -73,11 +85,8 @@ typedef struct __packed { uint32_t log_addr; /* physical addr of log or NULL if none */ uint32_t shutdown_entry; /* entry point for tboot shutdown */ uint32_t shutdown_type; /* type of shutdown (TB_SHUTDOWN_*) */ - uint32_t s3_tb_wakeup_entry;/* entry point for tboot s3 wake up */ - uint32_t s3_k_wakeup_entry; /* entry point for xen s3 wake up */ - tboot_acpi_sleep_info + tboot_acpi_sleep_info_t acpi_sinfo; /* where kernel put acpi sleep info in Sx */ - uint8_t reserved[52]; /* this pad is for compat with old field */ uint32_t tboot_base; /* starting addr for tboot */ uint32_t tboot_size; /* size of tboot */ } tboot_shared_t; @@ -122,10 +131,6 @@ static inline void print_tboot_shared(tb printk("\t log_addr: 0x%08x\n", tboot_shared->log_addr); printk("\t shutdown_entry: 0x%08x\n", tboot_shared->shutdown_entry); printk("\t shutdown_type: %d\n", tboot_shared->shutdown_type); - printk("\t s3_tb_wakeup_entry: 0x%08x\n", - tboot_shared->s3_tb_wakeup_entry); - printk("\t s3_k_wakeup_entry: 0x%08x\n", tboot_shared->s3_k_wakeup_entry); - printk("\t &acpi_sinfo: 0x%p\n", &tboot_shared->acpi_sinfo); printk("\t tboot_base: 0x%08x\n", tboot_shared->tboot_base); printk("\t tboot_size: 0x%x\n", tboot_shared->tboot_size); } diff -r c82b6c6847b2 -r a5551650862a tboot/common/acpi.c --- a/tboot/common/acpi.c Wed Jan 28 21:14:39 2009 -0800 +++ b/tboot/common/acpi.c Wed Jan 28 22:07:25 2009 -0800 @@ -1,8 +1,10 @@ /* * from xen/arch/x86/acpi/boot.c * drivers/acpi/tables.c + * drivers/acpi/hwregs.c + * drivers/acpi/osl.c * - * Copyright(c) 2008 Intel Corporation. All rights reserved. + * Copyright(c) 2008-2009 Intel Corporation. All rights reserved. * Copyright (C) 2001, 2002 Paul Diefenbaugh * Copyright (C) 2001 Jun Nakajima * @@ -42,6 +44,8 @@ #define ACPI_RSDT_TABLE_SIG "RSDT" #define ACPI_MADT_TABLE_SIG "APIC" +/* used by various fns below */ +static const tboot_acpi_sleep_info_t* g_acpi_sinfo; static unsigned long acpi_scan_rsdp(unsigned long start, unsigned long length) { @@ -327,25 +331,318 @@ uint32_t get_acpi_ioapic_table(void) #define ACPI_BITMASK_WAKE_STATUS 0x8000 #define ACPI_BITPOSITION_WAKE_STATUS 0x0F -static int acpi_get_wake_status(const tboot_acpi_sleep_info* acpi_info) +static acpi_status acpi_read_port(acpi_io_address port, u32* value, u32 width) { - uint16_t val; + if ( !value ) + return AE_ERROR; + + *value = 0; + if ( width <= 8 ) + *(u8 *)value = inb(port); + else if ( width <= 16 ) + *(u16 *)value = inw(port); + else if ( width <= 32 ) + *(u32 *)value = in(port); + else + return AE_ERROR; + + return AE_OK; +} + +static acpi_status acpi_write_port(acpi_io_address port, u32 value, u32 width) +{ + switch ( width ) { + case 8: + outb(value, port); + break; + case 16: + outw(value, port); + break; + case 32: + out(value, port); + break; + default: + return AE_ERROR; + } + + return AE_OK; +} + +static acpi_status +acpi_read_memory(acpi_physical_address addr, u32* value, u32 width) +{ + if ( !value ) + return AE_ERROR; + + *value = 0; + if ( width <= 8 ) + *(u8 *)value = readb(addr); + else if ( width <= 16 ) + *(u16 *)value = readw(addr); + else if ( width <= 32 ) + *(u32 *)value = readl(addr); + else + return AE_ERROR; + + return AE_OK; +} + +static acpi_status +acpi_write_memory(acpi_physical_address addr, u32 value, u32 width) +{ + switch ( width ) { + case 8: + writeb(value, addr); + break; + case 16: + writew(value, addr); + break; + case 32: + writel(value, addr); + break; + default: + return AE_ERROR; + } + + return AE_OK; +} + +static acpi_status +acpi_hw_low_level_read(u32 width, u32* value, + const tboot_acpi_generic_address_t* reg) +{ + u64 address; + acpi_status status; + + /* + * Must have a valid pointer to a GAS structure, and + * a non-zero address within. However, don't return an error + * because the PM1A/B code must not fail if B isn't present. + */ + if ( !reg ) + return AE_OK; + + /* Get a local copy of the address. Handles possible alignment issues */ + ACPI_MOVE_64_TO_64(&address, ®->address); + if ( !address ) + return AE_OK; + + *value = 0; + switch ( reg->space_id ) { + case ACPI_ADR_SPACE_SYSTEM_MEMORY: + status = acpi_read_memory( + (acpi_physical_address)(unsigned long)address, + value, width); + break; + case ACPI_ADR_SPACE_SYSTEM_IO: + status = acpi_read_port((acpi_io_address)address, + value, width); + break; + default: + return AE_BAD_PARAMETER; + } + + return status; +} + +static acpi_status +acpi_hw_low_level_write(u32 width, u32 value, + const tboot_acpi_generic_address_t* reg) +{ + u64 address; + acpi_status status; + + /* + * Must have a valid pointer to a GAS structure, and + * a non-zero address within. However, don't return an error + * because the PM1A/B code must not fail if B isn't present. + */ + if ( !reg ) + return AE_OK; + + /* Get a local copy of the address. Handles possible alignment issues */ + ACPI_MOVE_64_TO_64(&address, ®->address); + if ( !address ) + return AE_OK; + + switch ( reg->space_id ) { + case ACPI_ADR_SPACE_SYSTEM_MEMORY: + status = acpi_write_memory( + (acpi_physical_address)(unsigned long)address, + value, width); + break; + case ACPI_ADR_SPACE_SYSTEM_IO: + status = acpi_write_port((acpi_io_address)address, + value, width); + break; + default: + return AE_BAD_PARAMETER; + } + + return status; +} + +static acpi_status +acpi_hw_register_read(u32 register_id, u32* value) +{ + u32 value1 = 0; + u32 value2 = 0; + acpi_status status; + + if ( !value ) + return AE_ERROR; + + switch ( register_id ) { + case ACPI_REGISTER_PM1_STATUS: /* 16-bit access */ + status = acpi_hw_low_level_read(16, &value1, + &g_acpi_sinfo->pm1a_evt_blk); + if ( ACPI_FAILURE(status) ) + goto exit; + /* PM1B is optional */ + status = acpi_hw_low_level_read(16, &value2, + &g_acpi_sinfo->pm1b_evt_blk); + value1 |= value2; + break; + + case ACPI_REGISTER_PM1_CONTROL: /* 16-bit access */ + status = acpi_hw_low_level_read(16, &value1, + &g_acpi_sinfo->pm1a_cnt_blk); + if ( ACPI_FAILURE(status) ) + goto exit; + status = acpi_hw_low_level_read(16, &value2, + &g_acpi_sinfo->pm1b_cnt_blk); + value1 |= value2; + break; + default: + status = AE_BAD_PARAMETER; + break; + } + +exit: + if ( ACPI_SUCCESS(status) ) + *value = value1; + + return status; +} + +static acpi_status +acpi_hw_register_write(u32 register_id, u32 value) +{ + u32 value1 = 0; + acpi_status status; + + switch ( register_id ) { + case ACPI_REGISTER_PM1_STATUS: /* 16-bit access */ + /* Perform a read first to preserve certain bits (per ACPI spec) */ + status = acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS, &value1); + if ( ACPI_FAILURE(status) ) + goto exit; + /* Insert the bits to be preserved */ + ACPI_INSERT_BITS(value, ACPI_PM1_STATUS_PRESERVED_BITS, value1); + /* Now we can write the data */ + status = acpi_hw_low_level_write(16, value, + &g_acpi_sinfo->pm1a_evt_blk); + if ( ACPI_FAILURE(status) ) + goto exit; + /* PM1B is optional */ + status = acpi_hw_low_level_write(16, value, + &g_acpi_sinfo->pm1b_evt_blk); + break; + case ACPI_REGISTER_PM1_CONTROL: /* 16-bit access */ + /* Perform a read first to preserve certain bits (per ACPI spec) */ + status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL, &value1); + if ( ACPI_FAILURE(status) ) + goto exit; + /* Insert the bits to be preserved */ + ACPI_INSERT_BITS(value, ACPI_PM1_CONTROL_PRESERVED_BITS, value1); + /* Now we can write the data */ + status = acpi_hw_low_level_write(16, value, + &g_acpi_sinfo->pm1a_cnt_blk); + if ( ACPI_FAILURE(status) ) + goto exit; + status = acpi_hw_low_level_write(16, value, + &g_acpi_sinfo->pm1b_cnt_blk); + break; + case ACPI_REGISTER_PM1A_CONTROL: /* 16-bit access */ + status = acpi_hw_low_level_write(16, value, + &g_acpi_sinfo->pm1a_cnt_blk); + break; + case ACPI_REGISTER_PM1B_CONTROL: /* 16-bit access */ + status = acpi_hw_low_level_write(16, value, + &g_acpi_sinfo->pm1b_cnt_blk); + break; + default: + status = AE_BAD_PARAMETER; + break; + } + +exit: + return status; +} + +static int acpi_get_wake_status(void) +{ + uint32_t val; + acpi_status status; /* Wake status is the 15th bit of PM1 status register. (ACPI spec 3.0) */ - val = inw(acpi_info->pm1a_evt) | inw(acpi_info->pm1b_evt); + status = acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS, &val); + if ( ACPI_FAILURE(status) ) + return 0; + val &= ACPI_BITMASK_WAKE_STATUS; val >>= ACPI_BITPOSITION_WAKE_STATUS; return val; } -void machine_sleep(const tboot_acpi_sleep_info* acpi_info) +acpi_status machine_sleep(const tboot_acpi_sleep_info_t* acpi_sinfo) { + acpi_status status; + wbinvd(); - outw((u16)acpi_info->pm1a_cnt_val, acpi_info->pm1a_cnt); - if ( acpi_info->pm1b_cnt ) - outw((u16)acpi_info->pm1b_cnt_val, acpi_info->pm1b_cnt); - - /* Wait until we enter sleep state, and spin until we wake */ - while ( !acpi_get_wake_status(acpi_info) ); + /* set for use by various ACPI fns above */ + g_acpi_sinfo = acpi_sinfo; + + status = acpi_hw_register_write(ACPI_REGISTER_PM1A_CONTROL, + g_acpi_sinfo->pm1a_cnt_val); + if ( ACPI_FAILURE(status) ) + return AE_ERROR; + + if ( g_acpi_sinfo->pm1b_cnt_blk.address ) { + status = acpi_hw_register_write(ACPI_REGISTER_PM1B_CONTROL, + g_acpi_sinfo->pm1b_cnt_val); + if ( ACPI_FAILURE(status) ) + return AE_ERROR; + } + + /* Wait until we enter sleep state; we should never return to here */ + while ( !acpi_get_wake_status() ) + continue; + + return AE_OK; } + +void set_s3_resume_vector(const tboot_acpi_sleep_info_t* acpi_sinfo, + uint64_t resume_vector) +{ + if ( acpi_sinfo->vector_width <= 32 ) + *(uint32_t *)(uintptr_t)acpi_sinfo->wakeup_vector = + (uint32_t)resume_vector; + else + *(uint64_t *)(uintptr_t)acpi_sinfo->wakeup_vector = + (uint64_t)resume_vector; + printk("kernel S3 resume vector: 0x%Lx\n", resume_vector); + printk("wakeup_vector: 0x%Lx\n", acpi_sinfo->wakeup_vector); +} + + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r c82b6c6847b2 -r a5551650862a tboot/common/early_printk.c --- a/tboot/common/early_printk.c Wed Jan 28 21:14:39 2009 -0800 +++ b/tboot/common/early_printk.c Wed Jan 28 22:07:25 2009 -0800 @@ -1,7 +1,7 @@ /* * early_printk.c: printk to serial for very early boot stages * - * Copyright (c) 2006-2007, Intel Corporation + * Copyright (c) 2006-2009, Intel Corporation * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -323,9 +323,6 @@ config_parsed: #define VGABASE 0xb8000 -#define readw(x) (*(volatile unsigned short *)(x)) -#define writew(d,x) (*(volatile unsigned short *)(x) = (d)) - static const int max_ypos = 25; static const int max_xpos = 80; diff -r c82b6c6847b2 -r a5551650862a tboot/common/tboot.c --- a/tboot/common/tboot.c Wed Jan 28 21:14:39 2009 -0800 +++ b/tboot/common/tboot.c Wed Jan 28 22:07:25 2009 -0800 @@ -83,6 +83,9 @@ extern tboot_shared_t _tboot_shared; * (s3_wakeup_end - s3_wakeup_16) can fit into one page. */ static __data uint8_t g_saved_s3_wakeup_page[PAGE_SIZE]; + +/* kernel/VMM's S3 resume addr */ +__data uint64_t g_kernel_s3_resume_vector; static tb_error_t verify_platform(void) @@ -217,7 +220,6 @@ static void post_launch(void) _tboot_shared.version = 3; _tboot_shared.log_addr = (uint32_t)g_log; _tboot_shared.shutdown_entry = (uint32_t)shutdown_entry; - _tboot_shared.s3_tb_wakeup_entry = (uint32_t)TBOOT_S3_WAKEUP_ADDR; _tboot_shared.tboot_base = (uint32_t)&_start; _tboot_shared.tboot_size = (uint32_t)&_end - (uint32_t)&_start; print_tboot_shared(&_tboot_shared); @@ -266,6 +268,10 @@ void begin_launch(multiboot_info_t *mbi) printk("command line: %s\n", g_cmdline); if ( s3_flag ) printk("resume from S3\n"); + + /* clear resume vector on S3 resume so any resets will not use it */ + if ( !is_launched() & s3_flag ) + set_s3_resume_vector(&_tboot_shared.acpi_sinfo, 0); /* we should only be executing on the BSP */ rdmsrl(MSR_IA32_APICBASE, apicbase); @@ -346,7 +352,7 @@ void s3_launch(void) print_tboot_shared(&_tboot_shared); - _prot_to_real(_tboot_shared.s3_k_wakeup_entry); + _prot_to_real(g_kernel_s3_resume_vector); } static void shutdown_system(uint32_t shutdown_type) @@ -365,9 +371,17 @@ static void shutdown_system(uint32_t shu switch( shutdown_type ) { case TB_SHUTDOWN_S3: copy_s3_wakeup_entry(); + /* save kernel resume vector and write ours to ACPI resume addr */ + g_kernel_s3_resume_vector = + _tboot_shared.acpi_sinfo.kernel_s3_resume_vector; + set_s3_resume_vector(&_tboot_shared.acpi_sinfo, + TBOOT_S3_WAKEUP_ADDR); + /* fall through for rest of Sx handling */ + case TB_SHUTDOWN_S4: case TB_SHUTDOWN_S5: machine_sleep(&_tboot_shared.acpi_sinfo); + /* if machine_sleep() fails, fall through to reset */ case TB_SHUTDOWN_REBOOT: if ( txt_is_powercycle_required() ) { diff -r c82b6c6847b2 -r a5551650862a tboot/common/tpm.c --- a/tboot/common/tpm.c Wed Jan 28 21:14:39 2009 -0800 +++ b/tboot/common/tpm.c Wed Jan 28 22:07:25 2009 -0800 @@ -1,7 +1,7 @@ /* * tpm.c: TPM-related support functions * - * Copyright (c) 2006-2007, Intel Corporation + * Copyright (c) 2006-2009, Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -64,9 +64,6 @@ #define TPM_TAG_PCR_INFO_LONG 0x0006 #define TPM_TAG_STORED_DATA12 0x0016 - -#define readb(x) (*(volatile char *)(x)) -#define writeb(d,x) (*(volatile char *)(x) = (d)) /* * TPM registers and data structures diff -r c82b6c6847b2 -r a5551650862a tboot/include/acpi.h --- a/tboot/include/acpi.h Wed Jan 28 21:14:39 2009 -0800 +++ b/tboot/include/acpi.h Wed Jan 28 22:07:25 2009 -0800 @@ -1,7 +1,7 @@ /* * acpi.h - ACPI Interface * - * Copyright(c) 2007 Intel Corporation. All rights reserved. + * Copyright(c) 2007-2009 Intel Corporation. All rights reserved. * Copyright (C) 2001 Paul Diefenbaugh * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -127,6 +127,118 @@ extern bool restore_vtd_dmar_table(void) extern bool restore_vtd_dmar_table(void); extern bool remove_vtd_dmar_table(void); -extern void machine_sleep(const tboot_acpi_sleep_info *acpi_info); + +/* + * Macros for moving data around to/from buffers that are possibly unaligned. + * If the hardware supports the transfer of unaligned data, just do the store. + * Otherwise, we have to move one byte at a time. + */ +#ifdef ACPI_BIG_ENDIAN +/* + * Macros for big-endian machines + */ + +/* These macros reverse the bytes during the move, converting little-endian to big endian */ + + /* Big Endian <== Little Endian */ + /* Hi...Lo Lo...Hi */ +#define ACPI_MOVE_64_TO_64(d,s) \ + {(( u8 *)(void *)(d))[0] = ((u8 *)(void *)(s))[7];\ + (( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[6];\ + (( u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[5];\ + (( u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[4];\ + (( u8 *)(void *)(d))[4] = ((u8 *)(void *)(s))[3];\ + (( u8 *)(void *)(d))[5] = ((u8 *)(void *)(s))[2];\ + (( u8 *)(void *)(d))[6] = ((u8 *)(void *)(s))[1];\ + (( u8 *)(void *)(d))[7] = ((u8 *)(void *)(s))[0];} +#else +/* + * Macros for little-endian machines + */ + +#ifndef ACPI_MISALIGNMENT_NOT_SUPPORTED + +/* The hardware supports unaligned transfers, just do the little-endian move */ + +/* 64-bit source, 64 destination */ +#define ACPI_MOVE_64_TO_64(d,s) \ + *(u64 *)(void *)(d) = *(u64 *)(void *)(s) + +#else +/* + * The hardware does not support unaligned transfers. We must move the + * data one byte at a time. These macros work whether the source or + * the destination (or both) is/are unaligned. (Little-endian move) + */ + +/* 64-bit source, 64 destination */ +#define ACPI_MOVE_64_TO_64(d,s) \ + {(( u8 *)(void *)(d))[0] = ((u8 *)(void *)(s))[0];\ + (( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[1];\ + (( u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[2];\ + (( u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[3];\ + (( u8 *)(void *)(d))[4] = ((u8 *)(void *)(s))[4];\ + (( u8 *)(void *)(d))[5] = ((u8 *)(void *)(s))[5];\ + (( u8 *)(void *)(d))[6] = ((u8 *)(void *)(s))[6];\ + (( u8 *)(void *)(d))[7] = ((u8 *)(void *)(s))[7];} +#endif +#endif + + + +#define ACPI_INSERT_BITS(target,mask,source) \ + target = ((target & (~(mask))) | (source & mask)) + + + +typedef u32 acpi_status; /* All ACPI Exceptions */ +#define AE_CODE_ENVIRONMENTAL 0x0000 +#define AE_CODE_PROGRAMMER 0x1000 +#define AE_OK (acpi_status)0x0000 +/* Environmental exceptions */ +#define AE_ERROR (acpi_status) (0x0001 | AE_CODE_ENVIRONMENTAL) +/* Programmer exceptions */ +#define AE_BAD_PARAMETER (acpi_status) (0x0001 | AE_CODE_PROGRAMMER) + +#define ACPI_SUCCESS(a) (!(a)) +#define ACPI_FAILURE(a) (a) + + + +typedef u8 acpi_adr_space_type; +#define ACPI_ADR_SPACE_SYSTEM_MEMORY (acpi_adr_space_type)0 +#define ACPI_ADR_SPACE_SYSTEM_IO (acpi_adr_space_type)1 + + + +/* + * Some ACPI registers have bits that must be ignored -- meaning that they + * must be preserved. + */ +#define ACPI_PM1_STATUS_PRESERVED_BITS 0x0800 /* Bit 11 */ +#define ACPI_PM1_CONTROL_PRESERVED_BITS 0x0200 /* Bit 9 (whatever) */ + +/* + * Register IDs + * These are the full ACPI registers + */ +#define ACPI_REGISTER_PM1_STATUS 0x01 +#define ACPI_REGISTER_PM1_ENABLE 0x02 +#define ACPI_REGISTER_PM1_CONTROL 0x03 +#define ACPI_REGISTER_PM1A_CONTROL 0x04 +#define ACPI_REGISTER_PM1B_CONTROL 0x05 +#define ACPI_REGISTER_PM2_CONTROL 0x06 +#define ACPI_REGISTER_PM_TIMER 0x07 +#define ACPI_REGISTER_PROCESSOR_BLOCK 0x08 +#define ACPI_REGISTER_SMI_COMMAND_BLOCK 0x09 + + +typedef unsigned short acpi_io_address; +typedef void * acpi_physical_address; + + +extern acpi_status machine_sleep(const tboot_acpi_sleep_info_t* acpi_sinfo); +extern void set_s3_resume_vector(const tboot_acpi_sleep_info_t* acpi_sinfo, + uint64_t resume_vector); #endif /* __ACPI_H__ */ diff -r c82b6c6847b2 -r a5551650862a tboot/include/misc.h --- a/tboot/include/misc.h Wed Jan 28 21:14:39 2009 -0800 +++ b/tboot/include/misc.h Wed Jan 28 22:07:25 2009 -0800 @@ -80,6 +80,16 @@ static inline void out(unsigned int valu __asm__ __volatile__ ("out %0, %w1" : : "a" (value), "Nd" (port)); } +/* + * from io.h + */ + +#define readb(x) (*(volatile char *)(x)) +#define readw(x) (*(volatile short *)(x)) +#define readl(x) (*(volatile int *)(x)) +#define writeb(d,x) (*(volatile char *)(x) = (d)) +#define writew(d,x) (*(volatile short *)(x) = (d)) +#define writel(d,x) (*(volatile int *)(x) = (d)) /* * from lib.h # HG changeset patch # User Joseph Cihula # Date 1233209448 28800 # Node ID 059e05acc18e9a16f836e22d6357f6dadd1de9c2 # Parent a5551650862acc762cbe6649b7332eb74d48b51c Change e820 memory type for TXT-related ranges (e.g. SINIT, TXT heap, TXT private config space) from E820_UNUSABLE to E820_RESERVED to allow for more flexibility of kernels/VMMs to control access to these regions Signed-off-by: Shane Wang Signed-off-by: Joseph Cihula diff -r a5551650862a -r 059e05acc18e tboot/txt/txt.c --- a/tboot/txt/txt.c Wed Jan 28 22:07:25 2009 -0800 +++ b/tboot/txt/txt.c Wed Jan 28 22:10:48 2009 -0800 @@ -703,7 +703,7 @@ tb_error_t txt_protect_mem_regions(void) 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_UNUSABLE) ) + if ( !e820_protect_region(base, size, E820_RESERVED) ) return TB_ERR_FATAL; /* SINIT */ @@ -711,7 +711,15 @@ tb_error_t txt_protect_mem_regions(void) 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_UNUSABLE) ) + if ( !e820_protect_region(base, size, E820_RESERVED) ) + return TB_ERR_FATAL; + + /* 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_RESERVED) ) return TB_ERR_FATAL; /* ensure that memory not marked as good RAM by the MDRs is RESERVED in @@ -727,14 +735,6 @@ tb_error_t txt_protect_mem_regions(void) return TB_ERR_POST_LAUNCH_VERIFICATION; } printk("verification succeeded.\n"); - - /* 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_UNUSABLE) ) - return TB_ERR_FATAL; /* if vtd_pmr_lo/hi sizes rounded to 2MB granularity are less than the max_lo/hi_ram values determined from the e820 table, then we must # HG changeset patch # User Joseph Cihula # Date 1233210665 28800 # Node ID d3ff29cdd3a0ff8939974b6487093e2d0d719f6f # Parent 059e05acc18e9a16f836e22d6357f6dadd1de9c2 Provide integrity protection to launched kernel/VMM during S3 Before entering S3, tboot will calculate a hash over regions of memory provided by the kernel and seal the hash. Upon resume, after re-establishing the measured environment, tboot will verify that the memory image of those regions match the sealed hash. Signed-off-by: Joseph Cihula Signed-off-by: Shane Wang diff -r 059e05acc18e -r d3ff29cdd3a0 include/tboot.h --- a/include/tboot.h Wed Jan 28 22:10:48 2009 -0800 +++ b/include/tboot.h Wed Jan 28 22:31:05 2009 -0800 @@ -57,6 +57,12 @@ typedef struct __packed { * used to communicate between tboot and the launched kernel (i.e. Xen) */ +#define MAX_TB_MAC_REGIONS 32 +typedef struct __packed { + uint64_t start; + uint64_t end; +} tboot_mac_region_t; + /* GAS - Generic Address Structure (ACPI 2.0+) */ typedef struct __packed { uint8_t space_id; @@ -89,6 +95,9 @@ typedef struct __packed { acpi_sinfo; /* where kernel put acpi sleep info in Sx */ uint32_t tboot_base; /* starting addr for tboot */ uint32_t tboot_size; /* size of tboot */ + uint8_t num_mac_regions; /* number mem regions to MAC on S3 */ + /* contig regions memory to MAC on S3 */ + tboot_mac_region_t mac_regions[MAX_TB_MAC_REGIONS]; } tboot_shared_t; #define TB_SHUTDOWN_REBOOT 0 diff -r 059e05acc18e -r d3ff29cdd3a0 tboot/common/integrity.c --- a/tboot/common/integrity.c Wed Jan 28 22:10:48 2009 -0800 +++ b/tboot/common/integrity.c Wed Jan 28 22:31:05 2009 -0800 @@ -2,7 +2,7 @@ * integrity.c: routines for memory integrity measurement & * verification. Memory integrity is protected with tpm seal * - * Copyright (c) 2007-2008, Intel Corporation + * Copyright (c) 2007-2009, Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -50,16 +50,23 @@ /* put in .data section to that they aren't cleared on S3 resume */ -/* hashes that are used to restore DRTM PCRs in S3 resume */ -__data s3_state_t g_s3_state; +/* state whose integrity needs to be maintained across S3 */ +__data pre_k_s3_state_t g_pre_k_s3_state; +__data post_k_s3_state_t g_post_k_s3_state; -static __data uint8_t sealed_vl[512]; -static __data uint32_t sealed_vl_size; +/* state sealed before extending PCRs and launching kernel */ +static __data uint8_t sealed_pre_k_state[512]; +static __data uint32_t sealed_pre_k_state_size; + +/* state sealed just before entering S3 (after kernel shuts down) */ +static __data uint8_t sealed_post_k_state[512]; +static __data uint32_t sealed_post_k_state_size; /* PCR 17+18 values post-launch and before extending (used to seal verified launch hashes and memory integrity UMAC) */ static __data tpm_pcr_value_t post_launch_pcr17, post_launch_pcr18; +extern tboot_shared_t _tboot_shared; extern bool hash_policy(tb_hash_t *hash, uint8_t hash_alg); @@ -73,9 +80,9 @@ static bool extend_pcrs(void) printk(" PCR 17: "); print_hash((tb_hash_t *)&pcr17, TB_HALG_SHA1); printk(" PCR 18: "); print_hash((tb_hash_t *)&pcr18, TB_HALG_SHA1); - for ( int i = 0; i < g_s3_state.num_vl_entries; i++ ) { - if ( tpm_pcr_extend(2, g_s3_state.vl_entries[i].pcr, - (tpm_pcr_value_t *)&g_s3_state.vl_entries[i].hash, + for ( int i = 0; i < g_pre_k_s3_state.num_vl_entries; i++ ) { + if ( tpm_pcr_extend(2, g_pre_k_s3_state.vl_entries[i].pcr, + (tpm_pcr_value_t *)&g_pre_k_s3_state.vl_entries[i].hash, NULL) != TPM_SUCCESS ) return false; } @@ -89,34 +96,111 @@ static bool extend_pcrs(void) return true; } +static void print_pre_k_s3_state(void) +{ + printk("pre_k_s3_state:\n"); + printk("\t vtd_pmr_lo_base: 0x%Lx\n", g_pre_k_s3_state.vtd_pmr_lo_base); + printk("\t vtd_pmr_lo_size: 0x%Lx\n", g_pre_k_s3_state.vtd_pmr_lo_size); + printk("\t vtd_pmr_hi_base: 0x%Lx\n", g_pre_k_s3_state.vtd_pmr_hi_base); + printk("\t vtd_pmr_hi_size: 0x%Lx\n", g_pre_k_s3_state.vtd_pmr_hi_size); + printk("\t pol_hash: "); + print_hash(&g_pre_k_s3_state.pol_hash, TB_HALG_SHA1); + printk("\t VL measurements:\n"); + for ( int i = 0; i < g_pre_k_s3_state.num_vl_entries; i++ ) { + printk("\t PCR %d: ", g_pre_k_s3_state.vl_entries[i].pcr); + print_hash(&g_pre_k_s3_state.vl_entries[i].hash, TB_HALG_SHA1); + } +} + +static void print_post_k_s3_state(void) +{ + printk("post_k_s3_state:\n"); + printk("\t kernel_s3_resume_vector: 0x%Lx\n", + g_post_k_s3_state.kernel_s3_resume_vector); + printk("\t kernel_integ:\n\t"); + print_hash(&g_post_k_s3_state.kernel_integ, TB_HALG_SHA1); +} + +static bool seal_data(const void *data, size_t data_size, + uint8_t *sealed_data, uint32_t *sealed_data_size, + const uint8_t pcr_indcs_create[], int nr_pcr_indcs_create, + const uint8_t pcr_indcs_release[], int nr_pcr_indcs_release, + const tpm_pcr_value_t *pcr_values_release[]) +{ + /* TPM_Seal can only seal small data (like key or hash), so hash data */ + tb_hash_t data_hash; + memset(&data_hash, 0, sizeof(data_hash)); + if ( !hash_buffer(data, data_size, &data_hash, TB_HALG_SHA1) ) { + printk("failed to hash data\n"); + return false; + } + + if ( tpm_seal(2, TPM_LOC_TWO, + nr_pcr_indcs_create, pcr_indcs_create, + nr_pcr_indcs_release, pcr_indcs_release, + pcr_values_release, + sizeof(data_hash), (const uint8_t *)&data_hash, + sealed_data_size, sealed_data) != TPM_SUCCESS ) { + printk("failed to seal data\n"); + return false; + } + + return true; +} + +static bool verify_sealed_data(const uint8_t *sealed_data, + uint32_t sealed_data_size, + const void *curr_data, + size_t curr_data_size) +{ + /* sealed data is hash of state data */ + tb_hash_t sealed_hash; + uint32_t data_size = sizeof(sealed_hash); + if ( tpm_unseal(2, sealed_data_size, sealed_data, + &data_size, (uint8_t *)&sealed_hash) != TPM_SUCCESS ) { + printk("failed to unseal hash\n"); + return false; + } + if ( data_size != sizeof(tb_hash_t) ) { + printk("unsealed state data size mismatch\n"); + return false; + } + + /* verify that (hash of) current data maches sealed hash */ + tb_hash_t curr_data_hash; + memset(&curr_data_hash, 0, sizeof(curr_data_hash)); + if ( !hash_buffer(curr_data, curr_data_size, &curr_data_hash, + TB_HALG_SHA1) ) { + printk("failed to hash state data\n"); + return false; + } + if ( !are_hashes_equal(&sealed_hash, &curr_data_hash, TB_HALG_SHA1) ) { + printk("sealed hash does not match current hash\n"); + return false; + } + + return true; +} + /* - * DRTM measurements (e.g. policy control field, policy, modules) and current - * policy (to prevent rollback) are sealed to PCRs 17+18 with post-launch - * values (i.e. before extending with above) + * pre- PCR extend/kernel launch S3 data are sealed to PCRs 17+18 with + * post-launch values (i.e. before extending) */ -bool seal_initial_measurements(void) +bool seal_pre_k_state(void) { - uint8_t pcr_indcs_create[] = {17, 18}; - uint8_t pcr_indcs_release[] = {17, 18}; + const uint8_t pcr_indcs_create[] = {17, 18}; + const uint8_t pcr_indcs_release[] = {17, 18}; const tpm_pcr_value_t *pcr_values_release[] = {&post_launch_pcr17, &post_launch_pcr18}; - /* save hash of current policy into g_s3_state */ - memset(&g_s3_state.pol_hash, 0, sizeof(g_s3_state.pol_hash)); - if ( !hash_policy(&g_s3_state.pol_hash, TB_HALG_SHA1) ) { + /* save hash of current policy into g_pre_k_s3_state */ + memset(&g_pre_k_s3_state.pol_hash, 0, sizeof(g_pre_k_s3_state.pol_hash)); + if ( !hash_policy(&g_pre_k_s3_state.pol_hash, TB_HALG_SHA1) ) { printk("failed to hash policy\n"); return false; } - /* we need to seal g_s3_state and the current policy (but TPM_Seal can - only seal small data like key or hash), so seal hash of hashes */ - tb_hash_t s3_state_hash; - memset(&s3_state_hash, 0, sizeof(s3_state_hash)); - if ( !hash_buffer((const unsigned char *)&g_s3_state, sizeof(g_s3_state), - &s3_state_hash, TB_HALG_SHA1) ) { - printk("failed to hash g_s3_state\n"); - return false; - } + print_pre_k_s3_state(); /* read PCR 17/18 */ if ( tpm_pcr_read(2, 17, &post_launch_pcr17) != TPM_SUCCESS ) @@ -124,14 +208,12 @@ bool seal_initial_measurements(void) if ( tpm_pcr_read(2, 18, &post_launch_pcr18) != TPM_SUCCESS ) return false; - /* seal to locality 2, PCRs 17/18 */ - sealed_vl_size = sizeof(sealed_vl); - if ( tpm_seal(2, TPM_LOC_TWO, - ARRAY_SIZE(pcr_indcs_create), pcr_indcs_create, - ARRAY_SIZE(pcr_indcs_release), pcr_indcs_release, - pcr_values_release, - sizeof(s3_state_hash), (const uint8_t *)&s3_state_hash, - &sealed_vl_size, sealed_vl) != TPM_SUCCESS ) + sealed_pre_k_state_size = sizeof(sealed_pre_k_state); + if ( !seal_data(&g_pre_k_s3_state, sizeof(g_pre_k_s3_state), + sealed_pre_k_state, &sealed_pre_k_state_size, + pcr_indcs_create, ARRAY_SIZE(pcr_indcs_create), + pcr_indcs_release, ARRAY_SIZE(pcr_indcs_release), + pcr_values_release) ) return false; if ( !extend_pcrs() ) @@ -140,41 +222,91 @@ bool seal_initial_measurements(void) return true; } +static bool measure_memory_integrity(tb_hash_t *hash) +{ + memset(hash, 0, sizeof(*hash)); + + for ( unsigned int i = 0; i < _tboot_shared.num_mac_regions; i++ ) { + tb_hash_t reg_hash; + uint64_t start = _tboot_shared.mac_regions[i].start; + uint64_t end = _tboot_shared.mac_regions[i].end; + + printk("SHAing region %u: 0x%Lx - 0x%Lx\n", i, start, end); + /* TBD: don't handle addrs > 4GB yet, so error */ + if ( (start & 0xffffffff00000000L) || (end & 0xffffffff00000000L) ) { + printk("range is in memory > 4GB\n"); + return false; + } + if ( !hash_buffer((const unsigned char *)(uintptr_t)start, end - start, + ®_hash, TB_HALG_SHA1) ) { + printk("failed to hash region\n"); + return false; + } + if ( !extend_hash(hash, ®_hash, TB_HALG_SHA1) ) { + printk("failed to extend hash\n"); + return false; + } + } + + printk("hash of regions is:\n\t"); + print_hash(hash, TB_HALG_SHA1); + + return true; +} + /* - * verify sealed VL msmnts and policy, then re-extend hashes + * verify memory integrity and sealed VL hashes, then re-extend hashes * * this must be called post-launch but before extending any modules or other * measurements into PCRs */ bool verify_integrity(void) { - uint32_t data_size; + unsigned int i; + uint8_t pcr_indcs_create[] = {17, 18}; + tpm_pcr_value_t pcr17, pcr18; + const tpm_pcr_value_t *pcr_values_create[] = {&pcr17, &pcr18}; - /* - * unseal and verify VL measurements - */ + /* verify integrity of pre-kernel state data */ + printk("verifying pre_k_s3_state\n"); + if ( !verify_sealed_data(sealed_pre_k_state, sealed_pre_k_state_size, + &g_pre_k_s3_state, sizeof(g_pre_k_s3_state)) ) + return false; - /* sealed data is hash of g_s3_state */ - tb_hash_t sealed_hash; - data_size = sizeof(sealed_hash); - if ( tpm_unseal(2, sealed_vl_size, sealed_vl, - &data_size, (uint8_t *)&sealed_hash) != TPM_SUCCESS ) - return false; - if ( data_size != sizeof(tb_hash_t) ) { - printk("unsealed data size mismatch\n"); + /* to prevent rollback attack using old sealed measurements, + verify that (creation) PCRs at mem integrity seal time are same as + if we extend current PCRs with unsealed VL measurements */ + /* TBD: we should check all DRTM PCRs */ + tpm_pcr_read(2, 17, &pcr17); + tpm_pcr_read(2, 18, &pcr18); + for ( i = 0; i < g_pre_k_s3_state.num_vl_entries; i++ ) { + if ( g_pre_k_s3_state.vl_entries[i].pcr == 17 ) + extend_hash((tb_hash_t *)&pcr17, + &g_pre_k_s3_state.vl_entries[i].hash, TB_HALG_SHA1); + else if ( g_pre_k_s3_state.vl_entries[i].pcr == 18 ) + extend_hash((tb_hash_t *)&pcr18, + &g_pre_k_s3_state.vl_entries[i].hash, TB_HALG_SHA1); + } + if ( !tpm_cmp_creation_pcrs(ARRAY_SIZE(pcr_indcs_create), + pcr_indcs_create, pcr_values_create, + sealed_post_k_state_size, + sealed_post_k_state) ) { + printk("extended PCR values don't match creation values in sealed blob.\n"); return false; } - /* verify that VL measurements and current policy match unsealed hash */ - tb_hash_t s3_state_hash; - memset(&s3_state_hash, 0, sizeof(s3_state_hash)); - if ( !hash_buffer((const unsigned char *)&g_s3_state, sizeof(g_s3_state), - &s3_state_hash, TB_HALG_SHA1) ) { - printk("failed to hash g_s3_state\n"); + /* verify integrity of post-kernel state data */ + printk("verifying post_k_s3_state\n"); + if ( !verify_sealed_data(sealed_post_k_state, sealed_post_k_state_size, + &g_post_k_s3_state, sizeof(g_post_k_s3_state)) ) return false; - } - if ( !are_hashes_equal(&sealed_hash, &s3_state_hash, TB_HALG_SHA1) ) { - printk("sealed hash does not match current hash\n"); + + /* Verify memory integrity against sealed value */ + tb_hash_t hash; + if ( !measure_memory_integrity(&hash) ) + return false; + if ( memcmp(&hash, &g_post_k_s3_state.kernel_integ, sizeof(hash)) ) { + printk("memory integrity lost on S3 resume\n"); return false; } @@ -185,13 +317,40 @@ bool verify_integrity(void) return true; } -void display_vl_msmnts(void) +/* + * post- kernel launch S3 state is sealed to PCRs 17+18 with post-launch + * values (i.e. before extending with VL hashes) + */ +bool seal_post_k_state(void) { - printk("g_s3_state:\n"); - for ( int i = 0; i < g_s3_state.num_vl_entries; i++ ) { - printk("\t PCR %d: ", g_s3_state.vl_entries[i].pcr); - print_hash(&g_s3_state.vl_entries[i].hash, TB_HALG_SHA1); + const uint8_t pcr_indcs_create[] = {17, 18}; + const uint8_t pcr_indcs_release[] = {17, 18}; + const tpm_pcr_value_t *pcr_values_release[] = {&post_launch_pcr17, + &post_launch_pcr18}; + + /* since tboot relies on the module it launches for resource protection, + that module should have at least one region for itself, otherwise + it will not be protected against S3 resume attacks */ + if ( _tboot_shared.num_mac_regions == 0 ) { + printk("no memory regions to MAC\n"); + return false; } + + /* calculate the memory integrity hash */ + if ( !measure_memory_integrity(&g_post_k_s3_state.kernel_integ) ) + return false; + + print_post_k_s3_state(); + + sealed_post_k_state_size = sizeof(sealed_post_k_state); + if ( !seal_data(&g_post_k_s3_state, sizeof(g_post_k_s3_state), + sealed_post_k_state, &sealed_post_k_state_size, + pcr_indcs_create, ARRAY_SIZE(pcr_indcs_create), + pcr_indcs_release, ARRAY_SIZE(pcr_indcs_release), + pcr_values_release) ) + return false; + + return true; } diff -r 059e05acc18e -r d3ff29cdd3a0 tboot/common/policy.c --- a/tboot/common/policy.c Wed Jan 28 22:10:48 2009 -0800 +++ b/tboot/common/policy.c Wed Jan 28 22:31:05 2009 -0800 @@ -399,12 +399,12 @@ static tb_error_t verify_module(module_t we'll just drop it if the list is full, but that will mean S3 resume PCRs won't match pre-S3 NULL pol_entry means this is module 0 which is extended to PCR 18 */ - if ( g_s3_state.num_vl_entries >= MAX_VL_HASHES ) + if ( g_pre_k_s3_state.num_vl_entries >= MAX_VL_HASHES ) printk("\t too many hashes to save\n"); else if ( pol_entry == NULL || pol_entry->pcr != TB_POL_PCR_NONE ) { uint8_t pcr = (pol_entry == NULL ) ? 18 : pol_entry->pcr; - g_s3_state.vl_entries[g_s3_state.num_vl_entries].pcr = pcr; - g_s3_state.vl_entries[g_s3_state.num_vl_entries++].hash = hash; + g_pre_k_s3_state.vl_entries[g_pre_k_s3_state.num_vl_entries].pcr = pcr; + g_pre_k_s3_state.vl_entries[g_pre_k_s3_state.num_vl_entries++].hash = hash; } if ( pol_entry != NULL && @@ -437,11 +437,11 @@ void verify_all_modules(multiboot_info_t } } if ( !hash_buffer(buf, get_hash_size(TB_HALG_SHA1) + - sizeof(g_policy->policy_control), - &g_s3_state.vl_entries[g_s3_state.num_vl_entries].hash, - TB_HALG_SHA1) ) + sizeof(g_policy->policy_control), + &g_pre_k_s3_state.vl_entries[g_pre_k_s3_state.num_vl_entries].hash, + TB_HALG_SHA1) ) apply_policy(TB_ERR_MODULE_VERIFICATION_FAILED); - g_s3_state.vl_entries[g_s3_state.num_vl_entries++].pcr = 17; + g_pre_k_s3_state.vl_entries[g_pre_k_s3_state.num_vl_entries++].pcr = 17; /* module 0 is always extended to PCR 18, so add entry for it */ apply_policy(verify_module(get_module(mbi, 0), NULL, g_policy->hash_alg)); @@ -463,8 +463,6 @@ void verify_all_modules(multiboot_info_t } printk("all modules are verified\n"); - - display_vl_msmnts(); } diff -r 059e05acc18e -r d3ff29cdd3a0 tboot/common/tboot.c --- a/tboot/common/tboot.c Wed Jan 28 22:10:48 2009 -0800 +++ b/tboot/common/tboot.c Wed Jan 28 22:31:05 2009 -0800 @@ -83,9 +83,6 @@ extern tboot_shared_t _tboot_shared; * (s3_wakeup_end - s3_wakeup_16) can fit into one page. */ static __data uint8_t g_saved_s3_wakeup_page[PAGE_SIZE]; - -/* kernel/VMM's S3 resume addr */ -__data uint64_t g_kernel_s3_resume_vector; static tb_error_t verify_platform(void) @@ -209,7 +206,7 @@ static void post_launch(void) /* * seal hashes of modules and VL policy to current value of PCR17 & 18 */ - if ( !seal_initial_measurements() ) + if ( !seal_pre_k_state() ) apply_policy(TB_ERR_S3_INTEGRITY); /* @@ -352,7 +349,7 @@ void s3_launch(void) print_tboot_shared(&_tboot_shared); - _prot_to_real(g_kernel_s3_resume_vector); + _prot_to_real(g_post_k_s3_state.kernel_s3_resume_vector); } static void shutdown_system(uint32_t shutdown_type) @@ -371,9 +368,7 @@ static void shutdown_system(uint32_t shu switch( shutdown_type ) { case TB_SHUTDOWN_S3: copy_s3_wakeup_entry(); - /* save kernel resume vector and write ours to ACPI resume addr */ - g_kernel_s3_resume_vector = - _tboot_shared.acpi_sinfo.kernel_s3_resume_vector; + /* write our S3 resume vector to ACPI resume addr */ set_s3_resume_vector(&_tboot_shared.acpi_sinfo, TBOOT_S3_WAKEUP_ADDR); /* fall through for rest of Sx handling */ @@ -416,10 +411,11 @@ static void cap_pcrs(void) /* also cap every dynamic PCR we extended (only once) */ /* don't cap static PCRs since then they would be wrong after S3 resume */ memset(&was_capped, true, TPM_PCR_RESETABLE_MIN*sizeof(bool)); - for ( int i = 0; i < g_s3_state.num_vl_entries; i++ ) { - if ( !was_capped[g_s3_state.vl_entries[i].pcr] ) { - tpm_pcr_extend(2, g_s3_state.vl_entries[i].pcr, &cap_val, NULL); - was_capped[g_s3_state.vl_entries[i].pcr] = true; + for ( int i = 0; i < g_pre_k_s3_state.num_vl_entries; i++ ) { + if ( !was_capped[g_pre_k_s3_state.vl_entries[i].pcr] ) { + tpm_pcr_extend(2, g_pre_k_s3_state.vl_entries[i].pcr, &cap_val, + NULL); + was_capped[g_pre_k_s3_state.vl_entries[i].pcr] = true; } } @@ -441,6 +437,14 @@ void shutdown(void) /* restore DMAR table if needed */ restore_vtd_dmar_table(); + + /* save kernel/VMM resume vector for sealing */ + g_post_k_s3_state.kernel_s3_resume_vector = + _tboot_shared.acpi_sinfo.kernel_s3_resume_vector; + + /* create and seal memory integrity measurement */ + if ( !seal_post_k_state() ) + apply_policy(TB_ERR_S3_INTEGRITY); } /* cap dynamic PCRs extended as part of launch (17, 18, ...) */ diff -r 059e05acc18e -r d3ff29cdd3a0 tboot/include/integrity.h --- a/tboot/include/integrity.h Wed Jan 28 22:10:48 2009 -0800 +++ b/tboot/include/integrity.h Wed Jan 28 22:31:05 2009 -0800 @@ -2,7 +2,7 @@ * integrity.h: routines for memory integrity measurement & * verification. Memory integrity is protected with tpm seal * - * Copyright (c) 2007-2008, Intel Corporation + * Copyright (c) 2007-2009, Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -38,10 +38,8 @@ #define _TBOOT_INTEGRITY_H_ /* - * hashes that we extend into DRTM PCRs and so need to preserve across S3 - * for verified launch (VL) - * a given PCR may have more than one hash and will get extended in the order - * it appears in the list + * state that must be saved across S3 and will be sealed for integrity + * before extending PCRs and launching kernel */ #define MAX_VL_HASHES 32 @@ -53,19 +51,32 @@ typedef struct { uint64_t vtd_pmr_hi_size; /* VL policy at time of sealing */ tb_hash_t pol_hash; - /* verified launch measurements to be re-extended in DRTM PCRs */ + /* verified launch measurements to be re-extended in DRTM PCRs + * a given PCR may have more than one hash and will get extended in the + * order it appears in the list */ uint8_t num_vl_entries; struct { uint8_t pcr; tb_hash_t hash; } vl_entries[MAX_VL_HASHES]; -} s3_state_t; +} pre_k_s3_state_t; -extern s3_state_t g_s3_state; +/* + * state that must be saved across S3 and will be sealed for integrity + * just before entering S3 (after kernel shuts down) + */ +typedef struct { + uint64_t kernel_s3_resume_vector; + tb_hash_t kernel_integ; +} post_k_s3_state_t; -extern bool seal_initial_measurements(void); + +extern pre_k_s3_state_t g_pre_k_s3_state; +extern post_k_s3_state_t g_post_k_s3_state; + +extern bool seal_pre_k_state(void); +extern bool seal_post_k_state(void); extern bool verify_integrity(void); -extern void display_vl_msmnts(void); #endif /* _TBOOT_INTEGRITY_H_ */ diff -r 059e05acc18e -r d3ff29cdd3a0 tboot/txt/verify.c --- a/tboot/txt/verify.c Wed Jan 28 22:10:48 2009 -0800 +++ b/tboot/txt/verify.c Wed Jan 28 22:31:05 2009 -0800 @@ -221,10 +221,10 @@ static bool verify_vtd_pmrs(txt_heap_t * /* calculate what they should have been */ /* no e820 table on S3 resume, so use saved (sealed) values */ if ( s3_flag ) { - min_lo_ram = g_s3_state.vtd_pmr_lo_base; - max_lo_ram = min_lo_ram + g_s3_state.vtd_pmr_lo_size; - min_hi_ram = g_s3_state.vtd_pmr_hi_base; - max_hi_ram = min_hi_ram + g_s3_state.vtd_pmr_hi_size; + min_lo_ram = g_pre_k_s3_state.vtd_pmr_lo_base; + max_lo_ram = min_lo_ram + g_pre_k_s3_state.vtd_pmr_lo_size; + min_hi_ram = g_pre_k_s3_state.vtd_pmr_hi_base; + max_hi_ram = min_hi_ram + g_pre_k_s3_state.vtd_pmr_hi_size; } else { os_mle_data_t *os_mle_data = get_os_mle_data_start(txt_heap); @@ -254,10 +254,10 @@ static bool verify_vtd_pmrs(txt_heap_t * if ( !s3_flag ) { /* save the verified values so that they can be sealed for S3 */ - g_s3_state.vtd_pmr_lo_base = os_sinit_data->vtd_pmr_lo_base; - g_s3_state.vtd_pmr_lo_size = os_sinit_data->vtd_pmr_lo_size; - g_s3_state.vtd_pmr_hi_base = os_sinit_data->vtd_pmr_hi_base; - g_s3_state.vtd_pmr_hi_size = os_sinit_data->vtd_pmr_hi_size; + g_pre_k_s3_state.vtd_pmr_lo_base = os_sinit_data->vtd_pmr_lo_base; + g_pre_k_s3_state.vtd_pmr_lo_size = os_sinit_data->vtd_pmr_lo_size; + g_pre_k_s3_state.vtd_pmr_hi_base = os_sinit_data->vtd_pmr_hi_base; + g_pre_k_s3_state.vtd_pmr_hi_size = os_sinit_data->vtd_pmr_hi_size; } return true;