From: Gang W. <gan...@in...> - 2011-10-19 08:18:34
|
changeset d3c1cfa15a25 in /var/www/tboot.hg details: tboot.hg?cmd=changeset;node=d3c1cfa15a25 description: Fix for GRUB2 loading elf image such as Xen. Tboot assumes all modules are loaded in the memory above tboot memory. It is true for GRUB1, but false for GRUB2. So for GRUB2 case, just move all modules & mbi in memory below tboot to the end of last module. It just apply to elf image case such as Xen, and not apply to Linux. For Linux there is a separate patch to fix potential issue with GRUB2. Signed-off-by: Gang Wei <gan...@in...> diffstat: include/config.h | 5 + tboot/common/loader.c | 153 +++++++++++++++++++++++++++++++++++++++++++++++++++ tboot/common/tboot.c | 12 +-- tboot/include/multiboot.h | 15 +++- 4 files changed, 174 insertions(+), 11 deletions(-) diffs (267 lines): diff -r d03f2f19188e -r d3c1cfa15a25 include/config.h --- a/include/config.h Thu Oct 13 23:30:18 2011 +0800 +++ b/include/config.h Wed Oct 19 16:13:16 2011 +0800 @@ -42,6 +42,8 @@ /* address tboot will load and execute at */ #define TBOOT_BASE_ADDR 0x0803000 +/* start address of tboot MLE page table, also the beginning of tboot memory */ +#define TBOOT_START ((unsigned long)&_start - 3*PAGE_SIZE) /* address that tboot will do s3 resume at */ /* (must be in lower 1MB (real mode) and less than Xen trampoline @ 0x8c000) */ @@ -75,6 +77,9 @@ .globl name; \ .align 16,0x90; \ name: +#else +extern char _start[]; /* start of tboot */ +extern char _end[]; /* end of tboot */ #endif diff -r d03f2f19188e -r d3c1cfa15a25 tboot/common/loader.c --- a/tboot/common/loader.c Thu Oct 13 23:30:18 2011 +0800 +++ b/tboot/common/loader.c Wed Oct 19 16:13:16 2011 +0800 @@ -248,6 +248,155 @@ return true; } +extern unsigned long get_tboot_mem_end(void); + +static bool below_tboot(unsigned long addr) +{ + return addr >= 0x100000 && addr < TBOOT_START; +} + +static unsigned long get_mbi_mem_end(multiboot_info_t *mbi) +{ + return ((unsigned long)mbi + 3*PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); +} + +static void fixup_modules(multiboot_info_t *mbi, size_t offset) +{ + for ( unsigned int i = 0; i < mbi->mods_count; i++ ) { + module_t *m = get_module(mbi, i); + if ( below_tboot(m->mod_start) ) { + m->mod_start += offset; + m->mod_end += offset; + } + if ( below_tboot(m->string) ) + m->string += offset; + } +} + +/* + * fixup_mbi() fn is to be called after modules and/or mbi are moved from below + * tboot memory to above tboot. It will fixup all pointers in mbi if mbi was + * moved; fixup modules table if any modules are moved. If mbi was moved, return + * the new mbi address otherwise return the old one. + */ +static multiboot_info_t *fixup_mbi(multiboot_info_t *mbi, size_t offset) +{ + bool moving_mbi = below_tboot((unsigned long)mbi); + + if ( moving_mbi ) { + printk("mbi was moved from %p to ", mbi); + mbi = (multiboot_info_t *)((unsigned long)mbi + offset); + printk("%p\n", mbi); + } + + if ( mbi->flags & MBI_MODULES ) { + if ( below_tboot(mbi->mods_addr) ) + mbi->mods_addr += offset; + fixup_modules(mbi, offset); + } + + if ( !moving_mbi ) + return mbi; + + /* tboot replace mmap_addr w/ a copy, and make a copy of cmdline */ + /* because we modify it. Those pointers don't need offset adjustment. */ + /* To make it general and depend less on such kind of changes, just check */ + /* whether we need to adjust offset before trying to do it for each field */ + if ( (mbi->flags & MBI_CMDLINE) && below_tboot(mbi->cmdline) ) + mbi->cmdline += offset; + + if ( (mbi->flags & MBI_AOUT) && below_tboot(mbi->syms.aout_image.addr) ) + mbi->syms.aout_image.addr += offset; + + if ( (mbi->flags & MBI_ELF) && below_tboot(mbi->syms.elf_image.addr) ) + mbi->syms.elf_image.addr += offset; + + if ( (mbi->flags & MBI_MEMMAP) && below_tboot(mbi->mmap_addr) ) + mbi->mmap_addr += offset; + + if ( (mbi->flags & MBI_DRIVES) && below_tboot(mbi->drives_addr) ) + mbi->drives_addr += offset; + + if ( (mbi->flags & MBI_CONFIG) && below_tboot(mbi->config_table) ) + mbi->config_table += offset; + + if ( (mbi->flags & MBI_BTLDNAME) && below_tboot(mbi->boot_loader_name) ) + mbi->boot_loader_name += offset; + + if ( (mbi->flags & MBI_APM) && below_tboot(mbi->apm_table) ) + mbi->apm_table += offset; + + if ( mbi->flags & MBI_VBE ) { + if ( below_tboot(mbi->vbe_control_info) ) + mbi->vbe_control_info += offset; + if ( below_tboot(mbi->vbe_mode_info) ) + mbi->vbe_mode_info += offset; + } + + return mbi; +} + +static uint32_t get_lowest_mod_start(multiboot_info_t *mbi) +{ + uint32_t lowest = 0xffffffff; + + for ( unsigned int i = 0; i < mbi->mods_count; i++ ) { + module_t *m = get_module(mbi, i); + if ( m->mod_start < lowest ) + lowest = m->mod_start; + } + + return lowest; +} + +static uint32_t get_highest_mod_end(multiboot_info_t *mbi) +{ + uint32_t highest = 0; + + for ( unsigned int i = 0; i < mbi->mods_count; i++ ) { + module_t *m = get_module(mbi, i); + if ( m->mod_end > highest ) + highest = m->mod_end; + } + + return highest; +} + +/* + * Move any mbi components/modules/mbi that are below tboot to just above tboot + */ +static void move_modules(multiboot_info_t **mbi) +{ + unsigned long lowest = get_lowest_mod_start(*mbi); + unsigned long from = 0; + + if ( below_tboot(lowest) ) + from = lowest; + else if ( below_tboot((unsigned long)*mbi) ) + from = (unsigned long)*mbi; + else + return; + + unsigned long highest = get_highest_mod_end(*mbi); + unsigned long to = (highest + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + + if ( to < get_tboot_mem_end() ) + to = get_tboot_mem_end(); + + /* + * assuming that all of the members of mbi (e.g. cmdline, + * syms.aout_image.addr, etc.) are contiguous with the mbi structure + */ + if ( to < get_mbi_mem_end(*mbi) ) + to = get_mbi_mem_end(*mbi); + + memcpy((void *)to, (void *)from, TBOOT_START - from); + + printk("0x%lx bytes copied from 0x%lx to 0x%lx\n", + TBOOT_START - from, from, to); + *mbi = fixup_mbi(*mbi, to - from); +} + bool launch_kernel(bool is_measured_launch) { enum { ELF, LINUX } kernel_type; @@ -267,12 +416,16 @@ if ( is_elf_image(kernel_image, kernel_size) ) { printk("kernel is ELF format\n"); kernel_type = ELF; + /* fix for GRUB2, which may load modules into memory before tboot */ + move_modules(&g_mbi); } else { printk("assuming kernel is Linux format\n"); kernel_type = LINUX; } + /* print_mbi(g_mbi); */ + kernel_image = remove_module(g_mbi, NULL); if ( kernel_image == NULL ) return false; diff -r d03f2f19188e -r d3c1cfa15a25 tboot/common/tboot.c --- a/tboot/common/tboot.c Thu Oct 13 23:30:18 2011 +0800 +++ b/tboot/common/tboot.c Wed Oct 19 16:13:16 2011 +0800 @@ -74,8 +74,6 @@ extern long s3_flag; -extern char _start[]; /* start of tboot */ -extern char _end[]; /* end of tboot */ extern char s3_wakeup_16[]; extern char s3_wakeup_end[]; @@ -95,9 +93,9 @@ */ static __data uint8_t g_saved_s3_wakeup_page[PAGE_SIZE]; -void *get_tboot_mem_end(void) +unsigned long get_tboot_mem_end(void) { - return (void *)(((unsigned long)&_end + PAGE_SIZE - 1ULL) & ~(PAGE_SIZE - 1)); + return ((unsigned long)&_end + PAGE_SIZE - 1ULL) & ~(PAGE_SIZE - 1); } static tb_error_t verify_platform(void) @@ -171,7 +169,7 @@ apply_policy(err); /* verify that tboot is in valid RAM (i.e. E820_RAM) */ - base = (uint64_t)((unsigned long)&_start - 3*PAGE_SIZE); + base = (uint64_t)TBOOT_START; size = (uint64_t)((unsigned long)&_end - base); printk("verifying tboot and its page table (%Lx - %Lx) in e820 table\n\t", base, (base + size - 1)); @@ -183,8 +181,8 @@ printk(": succeeded.\n"); /* protect ourselves, MLE page table, and MLE/kernel shared page */ - base = (uint64_t)((unsigned long)&_start - 3*PAGE_SIZE); - size = (uintptr_t)get_tboot_mem_end() - base; + base = (uint64_t)TBOOT_START; + size = (uint64_t)get_tboot_mem_end() - base; uint32_t mem_type = is_kernel_linux() ? E820_RESERVED : E820_UNUSABLE; printk("protecting tboot (%Lx - %Lx) in e820 table\n", base, (base + size - 1)); diff -r d03f2f19188e -r d3c1cfa15a25 tboot/include/multiboot.h --- a/tboot/include/multiboot.h Thu Oct 13 23:30:18 2011 +0800 +++ b/tboot/include/multiboot.h Wed Oct 19 16:13:16 2011 +0800 @@ -45,10 +45,17 @@ #define MULTIBOOT_HEADER_WANT_MEMORY 0x2 /* bit definitions of flags field of multiboot information */ -#define MBI_MEMLIMITS (1<<0) -#define MBI_CMDLINE (1<<2) -#define MBI_MODULES (1<<3) -#define MBI_MEMMAP (1<<6) +#define MBI_MEMLIMITS (1<<0) +#define MBI_CMDLINE (1<<2) +#define MBI_MODULES (1<<3) +#define MBI_AOUT (1<<4) +#define MBI_ELF (1<<5) +#define MBI_MEMMAP (1<<6) +#define MBI_DRIVES (1<<7) +#define MBI_CONFIG (1<<8) +#define MBI_BTLDNAME (1<<9) +#define MBI_APM (1<<10) +#define MBI_VBE (1<<11) #ifndef __ASSEMBLY__ |