Screenshot instructions:
Windows
Mac
Red Hat Linux
Ubuntu
Click URL instructions:
Right-click on ad, choose "Copy Link", then paste here →
(This may not be possible with some types of ads)
From: Joseph Cihula <joseph.cihula@in...> - 2010-05-19 18:18:09
|
changeset 80227b22d733 in /var/www/tboot.hg details: tboot.hg?cmd=changeset;node=80227b22d733 description: Fix issue where tboot would appear to hang after SENTER on some BIOSes (due to DMA protecting legacy USB buffers) On some BIOSes, which have a type 1 (E820_RAM) entry above the e820 reserved regions that contain the legacy USB buffers, the original tboot code will cover the reserved regions with the PMRs. This causes those BIOSes to hang in SMM after SENTER. This change will not DMA protect any RAM regions above reserved regions (RAM <4GB and for reserved regions above 0x100000). And if it finds any such RAM regions, it will mark them as reserved so that the kernel/VMM doesn't use them (since they aren't DMA protected). Signed-off-by: Joseph Cihula <joseph.cihula@...> diffstat: tboot/common/e820.c | 166 ++++++++++++++++++++++-------------------------------- tboot/common/linux.c | 2 +- tboot/common/tboot.c | 8 +- tboot/include/e820.h | 8 +- tboot/txt/txt.c | 6 +- tboot/txt/verify.c | 3 +- 6 files changed, 79 insertions(+), 114 deletions(-) diffs (truncated from 322 to 300 lines): diff -r d5bc75984c1d -r 80227b22d733 tboot/common/e820.c --- a/tboot/common/e820.c Tue Apr 27 16:29:24 2010 -0700 +++ b/tboot/common/e820.c Wed May 19 09:11:42 2010 -0700 @@ -268,15 +268,14 @@ */ bool copy_e820_map(multiboot_info_t *mbi) { - uint32_t entry_offset; + g_nr_map = 0; if ( mbi->flags & MBI_MEMMAP ) { printk("original e820 map:\n"); print_map((memory_map_t *)mbi->mmap_addr, mbi->mmap_length/sizeof(memory_map_t)); - g_nr_map = 0; - entry_offset = 0; + uint32_t entry_offset = 0; while ( entry_offset < mbi->mmap_length && g_nr_map < MAX_E820_ENTRIES ) { @@ -362,7 +361,7 @@ e820_base = 0; e820_length = 0; - for ( int i = 0; i < g_nr_map; i = gap?i:i+1, gap = !gap ) { + for ( int i = 0; i < g_nr_map; i = gap ? i : i+1, gap = !gap ) { e820_entry = &g_copy_e820_map[i]; if ( gap ) { /* deal with the gap in e820 map */ @@ -549,83 +548,76 @@ print_map(g_copy_e820_map, g_nr_map); } -bool get_ram_ranges(multiboot_info_t *mbi, - uint64_t *min_lo_ram, uint64_t *max_lo_ram, +bool get_ram_ranges(uint64_t *min_lo_ram, uint64_t *max_lo_ram, uint64_t *min_hi_ram, uint64_t *max_hi_ram) { - uint32_t entry_offset; - memory_map_t *entry; - uint64_t base, limit; - uint32_t map_addr; - uint32_t map_len; - if ( min_lo_ram == NULL || max_lo_ram == NULL || min_hi_ram == NULL || max_hi_ram == NULL ) return false; - if ( mbi == NULL || mbi->flags & MBI_MEMMAP ) { - entry_offset = 0; - *min_lo_ram = *min_hi_ram = ~0ULL; - *max_lo_ram = *max_hi_ram = 0; + *min_lo_ram = *min_hi_ram = ~0ULL; + *max_lo_ram = *max_hi_ram = 0; + bool found_reserved_region = false; - if ( mbi == NULL ) { - map_addr = (uint32_t)g_copy_e820_map; - map_len = g_nr_map * sizeof(memory_map_t); + for ( int i = 0; i < g_nr_map; i++ ) { + memory_map_t *entry = &g_copy_e820_map[i]; + uint64_t base = e820_base_64(entry); + uint64_t limit = base + e820_length_64(entry); + + if ( entry->type == E820_RAM ) { + /* if range straddles 4GB boundary, that is an error */ + if ( base < 0x100000000ULL && limit > 0x100000000ULL ) { + printk("e820 memory range straddles 4GB boundary\n"); + return false; + } + + /* + * some BIOSes put legacy USB buffers in reserved regions <4GB, + * which if DMA protected cause SMM to hang, so make sure that + * we don't overlap any of these even if that wastes RAM + */ + if ( !found_reserved_region ) { + if ( base < 0x100000000ULL && base < *min_lo_ram ) + *min_lo_ram = base; + if ( limit <= 0x100000000ULL && limit > *max_lo_ram ) + *max_lo_ram = limit; + } + else { /* need to reserve low RAM above reserved regions */ + if ( base < 0x100000000ULL ) { + printk("discarding RAM above reserved regions: 0x%Lx - 0x%Lx\n", base, limit); + if ( !e820_reserve_ram(base, limit - base) ) + return false; + } + } + + if ( base >= 0x100000000ULL && base < *min_hi_ram ) + *min_hi_ram = base; + if ( limit > 0x100000000ULL && limit > *max_hi_ram ) + *max_hi_ram = limit; } else { - map_addr = mbi->mmap_addr; - map_len = mbi->mmap_length; + /* parts of low memory may be reserved for cseg, ISA hole, + etc. but these seem OK to DMA protect, so ignore reserved + regions <0x100000 */ + if ( *min_lo_ram != ~0ULL && limit > 0x100000ULL ) + found_reserved_region = true; } + } - while ( entry_offset < map_len ) { - entry = (memory_map_t *)(map_addr + entry_offset); - if ( entry->type == E820_RAM ) { - base = e820_base_64(entry); - limit = base + e820_length_64(entry); - - /* if range straddles 4GB boundary, that is an error */ - if ( base < 0x100000000ULL && limit >= 0x100000000ULL ) { - printk("e820 memory range straddles 4GB boundary\n"); - return false; - } - - if ( base < 0x100000000ULL && base < *min_lo_ram ) - *min_lo_ram = base; - else if ( base >= 0x100000000ULL && base < *min_hi_ram ) - *min_hi_ram = base; - if ( limit < 0x100000000ULL && limit > *max_lo_ram ) - *max_lo_ram = limit; - else if ( limit >= 0x100000000ULL && limit > *max_hi_ram ) - *max_hi_ram = limit; - } - entry_offset += entry->size + sizeof(entry->size); - } - - /* no low RAM found */ - if ( *min_lo_ram >= *max_lo_ram ) { - printk("no low ram in e820 map\n"); - return false; - } - /* no high RAM found */ - if ( *min_hi_ram >= *max_hi_ram ) - *min_hi_ram = *max_hi_ram = 0; - } - else if ( mbi->flags & MBI_MEMLIMITS ) { - *min_lo_ram = 0; - *max_lo_ram = (((uint64_t)mbi->mem_upper) << 10) + 0x100000ULL; - *min_hi_ram = *max_hi_ram = 0; - } - else { - printk("no e820 map nor mem limits provided\n"); + /* no low RAM found */ + if ( *min_lo_ram >= *max_lo_ram ) { + printk("no low ram in e820 map\n"); return false; } + /* no high RAM found */ + if ( *min_hi_ram >= *max_hi_ram ) + *min_hi_ram = *max_hi_ram = 0; return true; } /* find highest (< <limit>) RAM region of at least <size> bytes */ -void get_highest_sized_ram(multiboot_info_t *mbi, - uint64_t size, uint64_t limit, +void get_highest_sized_ram(uint64_t size, uint64_t limit, uint64_t *ram_base, uint64_t *ram_size) { uint64_t last_fit_base = 0, last_fit_size = 0; @@ -633,43 +625,21 @@ if ( ram_base == NULL || ram_size == NULL ) return; - if ( mbi == NULL || mbi->flags & MBI_MEMMAP ) { - uint32_t map_addr; - uint32_t map_len; - uint32_t entry_offset = 0; + for ( int i = 0; i < g_nr_map; i++ ) { + memory_map_t *entry = &g_copy_e820_map[i]; - if ( mbi == NULL ) { - map_addr = (uint32_t)g_copy_e820_map; - map_len = g_nr_map * sizeof(memory_map_t); + if ( entry->type == E820_RAM ) { + uint64_t base = e820_base_64(entry); + uint64_t length = e820_length_64(entry); + + /* over 4GB so use the last region that fit */ + if ( base + length > limit ) + break; + if ( size <= length ) { + last_fit_base = base; + last_fit_size = length; + } } - else { - map_addr = mbi->mmap_addr; - map_len = mbi->mmap_length; - } - - while ( entry_offset < map_len ) { - memory_map_t *entry = (memory_map_t *)(map_addr + entry_offset); - if ( entry->type == E820_RAM ) { - uint64_t base = e820_base_64(entry); - uint64_t length = e820_length_64(entry); - - /* over 4GB so use the last region that fit */ - if ( base + length > limit ) - break; - if ( size <= length ) { - last_fit_base = base; - last_fit_size = length; - } - } - entry_offset += entry->size + sizeof(entry->size); - } - } - if ( last_fit_size == 0 && mbi->flags & MBI_MEMLIMITS ) { - last_fit_base = 0; - last_fit_size = (((uint64_t)mbi->mem_upper) << 10) + 0x100000ULL - - last_fit_base; - if ( last_fit_base + last_fit_size > limit ) - last_fit_size = limit - last_fit_base; } *ram_base = last_fit_base; diff -r d5bc75984c1d -r 80227b22d733 tboot/common/linux.c --- a/tboot/common/linux.c Tue Apr 27 16:29:24 2010 -0700 +++ b/tboot/common/linux.c Wed May 19 09:11:42 2010 -0700 @@ -152,7 +152,7 @@ mem_limit = 0x100000000ULL; uint64_t max_ram_base, max_ram_size; - get_highest_sized_ram(g_mbi, initrd_size, mem_limit, + get_highest_sized_ram(initrd_size, mem_limit, &max_ram_base, &max_ram_size); if ( max_ram_size == 0 ) { printk("not enough RAM for initrd\n"); diff -r d5bc75984c1d -r 80227b22d733 tboot/common/tboot.c --- a/tboot/common/tboot.c Tue Apr 27 16:29:24 2010 -0700 +++ b/tboot/common/tboot.c Wed May 19 09:11:42 2010 -0700 @@ -160,10 +160,6 @@ * verify e820 table and adjust it to protect our memory regions */ - /* make copy of e820 map that we will adjust */ - if ( !copy_e820_map(g_mbi) ) - apply_policy(TB_ERR_FATAL); - /* ensure all modules are in RAM */ if ( !verify_modules(g_mbi) ) apply_policy(TB_ERR_POST_LAUNCH_VERIFICATION); @@ -294,6 +290,10 @@ } printk("BSP is cpu %u\n", get_apicid()); + /* make copy of e820 map that we will use and adjust */ + if ( !copy_e820_map(g_mbi) ) + apply_policy(TB_ERR_FATAL); + /* we need to make sure this is a (TXT-) capable platform before using */ /* any of the features, incl. those required to check if the environment */ /* has already been launched */ diff -r d5bc75984c1d -r 80227b22d733 tboot/include/e820.h --- a/tboot/include/e820.h Tue Apr 27 16:29:24 2010 -0700 +++ b/tboot/include/e820.h Wed May 19 09:11:42 2010 -0700 @@ -62,7 +62,7 @@ #define E820MAX 128 -typedef struct __attribute__ ((packed)) { +typedef struct __packed { uint64_t addr; /* start of memory segment */ uint64_t size; /* size of memory segment */ uint32_t type; /* type of memory segment */ @@ -74,11 +74,9 @@ extern void print_e820_map(void); extern void replace_e820_map(multiboot_info_t *mbi); extern uint32_t e820_check_region(uint64_t base, uint64_t length); -extern bool get_ram_ranges(multiboot_info_t *mbi, - uint64_t *min_lo_ram, uint64_t *max_lo_ram, +extern bool get_ram_ranges(uint64_t *min_lo_ram, uint64_t *max_lo_ram, uint64_t *min_hi_ram, uint64_t *max_hi_ram); -extern void get_highest_sized_ram(multiboot_info_t *mbi, - uint64_t size, uint64_t limit, +extern void get_highest_sized_ram(uint64_t size, uint64_t limit, uint64_t *ram_base, uint64_t *ram_size); #endif /* __E820_H__ */ diff -r d5bc75984c1d -r 80227b22d733 tboot/txt/txt.c --- a/tboot/txt/txt.c Tue Apr 27 16:29:24 2010 -0700 +++ b/tboot/txt/txt.c Wed May 19 09:11:42 2010 -0700 @@ -332,8 +332,7 @@ (uint64_t)(unsigned long)&_mle_start; /* VT-d PMRs */ uint64_t min_lo_ram, max_lo_ram, min_hi_ram, max_hi_ram; - if ( !get_ram_ranges(mbi, &min_lo_ram, &max_lo_ram, &min_hi_ram, - &max_hi_ram) ) + if ( !get_ram_ranges(&min_lo_ram, &max_lo_ram, &min_hi_ram, &max_hi_ram) ) return NULL; set_vtd_pmrs(os_sinit_data, min_lo_ram, max_lo_ram, min_hi_ram, max_hi_ram); @@ -465,8 +464,7 @@ |