From 02f20279fec373a8b47b4b554fd5dac2e6504fbe Mon Sep 17 00:00:00 2001 From: neal Date: Wed, 25 Jul 2007 08:30:04 +0000 Subject: 2007-07-25 Neal H. Walfield * loader.h (relocate_region): New typedef. (loader_add_region): Add two additional arguments, rr and cookie. Update callers. * loader.c: Include "laden.h". (struct): Add fields rr, cookie and used. (check_region): Remove function. (loader_add_region): Allocate a region descriptor by checking whether the used bit is unset. Don't call check_region, check here if a region is okay. If there is overlap, move the other regions out of the way if possible. (loader_remove_region): Just set the used bit to zero. (loader_elf_load): Don't call check_region. Protect each segment individually. * ia32-cmain.c (cmain): Make a copy of the command line on the stack and pass that to main. (mbi_relocate): New function. (mods_relocate): Likewise. (cmdline_relocate): Likewise. (module_relocate): Likewise. (find_components): Protect the other modules. Protect each module's string individually. Protect the first page. * laden.c (rootserver_relocate): New function. * ia32-cmain.c (start_kernel): Before jumping to IP, load Grub's booloader magic into EAX and the address of the boot info structure into EBX. --- laden/ChangeLog | 33 +++++++++ laden/ia32-cmain.c | 105 +++++++++++++++++++++-------- laden/laden.c | 31 +++++++-- laden/loader.c | 192 ++++++++++++++++++++++++++++++++++++++++------------- laden/loader.h | 20 ++++-- 5 files changed, 296 insertions(+), 85 deletions(-) (limited to 'laden') diff --git a/laden/ChangeLog b/laden/ChangeLog index 39f75bd..f6216c2 100644 --- a/laden/ChangeLog +++ b/laden/ChangeLog @@ -1,3 +1,36 @@ +2007-07-25 Neal H. Walfield + + * laden.h (add_memory_map): Fix indentation. + +2007-07-25 Neal H. Walfield + + * loader.h (relocate_region): New typedef. + (loader_add_region): Add two additional arguments, rr and cookie. + Update callers. + * loader.c: Include "laden.h". + (struct): Add fields rr, cookie and used. + (check_region): Remove function. + (loader_add_region): Allocate a region descriptor by checking + whether the used bit is unset. Don't call check_region, check + here if a region is okay. If there is overlap, move the other + regions out of the way if possible. + (loader_remove_region): Just set the used bit to zero. + (loader_elf_load): Don't call check_region. Protect each segment + individually. + * ia32-cmain.c (cmain): Make a copy of the command line on the + stack and pass that to main. + (mbi_relocate): New function. + (mods_relocate): Likewise. + (cmdline_relocate): Likewise. + (module_relocate): Likewise. + (find_components): Protect the other modules. Protect each + module's string individually. Protect the first page. + * laden.c (rootserver_relocate): New function. + + * ia32-cmain.c (start_kernel): Before jumping to IP, load Grub's + booloader magic into EAX and the address of the boot info + structure into EBX. + 2005-01-22 Marcus Brinkmann * config.m4: Change to 0x190000 to make more room for a diff --git a/laden/ia32-cmain.c b/laden/ia32-cmain.c index c733c4b..1207dfe 100644 --- a/laden/ia32-cmain.c +++ b/laden/ia32-cmain.c @@ -1,12 +1,12 @@ /* ia32-cmain.c - Startup code for the ia32. - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2003, 2007 Free Software Foundation, Inc. Written by Marcus Brinkmann. This file is part of the GNU Hurd. The GNU Hurd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2, or (at + published by the Free Software Foundation; either version 3, or (at your option) any later version. The GNU Hurd is distributed in the hope that it will be useful, but @@ -47,10 +47,14 @@ start_kernel (l4_word_t ip) compatibility, but other architectures may not. If you are porting this file, make sure that the instruction fetcher gets to see the loaded kernel code. */ - asm volatile ("wbinvd"); - - /* Jump to the entry point. */ - (*(void (*) (void)) ip) (); + __asm__ __volatile__ ("wbinvd\n"); + /* Before jumping to IP, place the the address of the multiboot info + structure in ebx and the magic number in eax. This is required + by Fiasco (but not, e.g., Pistachio). */ + __asm__ __volatile__ ("jmp *%2\n" + : /* No output. */ + : "a" (MULTIBOOT_BOOTLOADER_MAGIC), + "b" (boot_info), "r" (ip)); } @@ -73,10 +77,16 @@ cmain (uint32_t magic, multiboot_info_t *mbi) if (!CHECK_FLAG (mbi->flags, 0) && !CHECK_FLAG (mbi->flags, 6)) panic ("Bootloader did not provide a memory map"); - if (CHECK_FLAG (mbi->flags, 2)) + if (CHECK_FLAG (mbi->flags, 2) && * (char *) mbi->cmdline) { /* A command line was passed. */ - char *str = (char *) mbi->cmdline; + + /* Make a copy on the local stack. Grub chooses an arbitrary + address which may conflict with the loaded executables. It + is difficult to relocate the command line as we may have + pointers into it. */ + char *str = alloca (strlen ((char *) mbi->cmdline) + 1); + memcpy (str, (char *) mbi->cmdline, strlen ((char *) mbi->cmdline) + 1); int nr = 0; /* First time around we count the number of arguments. */ @@ -180,6 +190,45 @@ debug_dump (void) extern char _start; extern char _end; +static void +mbi_relocate (const char *name, + l4_word_t start, l4_word_t end, l4_word_t new_start, + void *cookie) +{ + boot_info = new_start; +} + +static void +mods_relocate (const char *name, + l4_word_t start, l4_word_t end, l4_word_t new_start, + void *cookie) +{ + multiboot_info_t *mbi = (multiboot_info_t *) boot_info; + mbi->mods_addr = new_start; +} + +static void +cmdline_relocate (const char *name, + l4_word_t start, l4_word_t end, l4_word_t new_start, + void *cookie) +{ + multiboot_info_t *mbi = (multiboot_info_t *) boot_info; + module_t *mod = (module_t *) mbi->mods_addr; + l4_word_t i = (l4_word_t) cookie; + mod[i].string = new_start; +} + +static void +module_relocate (const char *name, + l4_word_t start, l4_word_t end, l4_word_t new_start, + void *cookie) +{ + multiboot_info_t *mbi = (multiboot_info_t *) boot_info; + module_t *mod = (module_t *) mbi->mods_addr; + l4_word_t i = (l4_word_t) cookie; + mod[i].mod_start = new_start; + mod[i].mod_end = new_start + (end - start); +} /* Find the kernel, the initial servers and the other information required for booting. */ @@ -221,6 +270,12 @@ find_components (void) rootserver.low = mod->mod_start; rootserver.high = mod->mod_end; } + + /* Add the rest of the modules. */ + int i; + for (i = 1; i < mbi->mods_count; i ++) + loader_add_region ("module", mod[i].mod_start, mod[i].mod_end, + module_relocate, (void *) (l4_word_t) i); } /* Now create the memory map. */ @@ -330,37 +385,31 @@ find_components (void) /* Now protect ourselves and the mulitboot info (at least the module configuration. */ - loader_add_region (program_name, (l4_word_t) &_start, (l4_word_t) &_end); + loader_add_region (program_name, (l4_word_t) &_start, (l4_word_t) &_end, + NULL, NULL); start = (l4_word_t) mbi; end = start + sizeof (*mbi); - loader_add_region ("grub-mbi", start, end); + loader_add_region ("grub-mbi", start, end, mbi_relocate, NULL); if (CHECK_FLAG (mbi->flags, 3) && mbi->mods_count) { module_t *mod = (module_t *) mbi->mods_addr; - int nr; start = (l4_word_t) mod; end = ((l4_word_t) mod) + mbi->mods_count * sizeof (*mod); - loader_add_region ("grub-mods", start, end); + loader_add_region ("grub-mods", start, end, mods_relocate, NULL); - start = (l4_word_t) mod[0].string; - end = start + 1; + l4_word_t nr; for (nr = 0; nr < mbi->mods_count; nr++) - { - char *str = (char *) mod[nr].string; - - if (str) - { - if (((l4_word_t) str) < start) - start = (l4_word_t) str; - while (*str) - str++; - if (((l4_word_t) str) + 1 > end) - end = (l4_word_t) str + 1; - } - } - loader_add_region ("grub-mods-cmdlines", start, end); + if (mod[nr].string) + loader_add_region ("grub-mods-cmdlines", + mod[nr].string, + mod[nr].string + strlen ((char *) mod[nr].string), + cmdline_relocate, (void *) nr); } + + /* Protect the first page. */ + loader_add_region ("first-page", (l4_word_t) 0, (l4_word_t) 0xfff, + NULL, NULL); } diff --git a/laden/laden.c b/laden/laden.c index 3552543..88b9874 100644 --- a/laden/laden.c +++ b/laden/laden.c @@ -1,12 +1,12 @@ /* laden.c - Main function for laden. - Copyright (C) 2003, 2005 Free Software Foundation, Inc. + Copyright (C) 2003, 2005, 2007 Free Software Foundation, Inc. Written by Marcus Brinkmann. This file is part of the GNU Hurd. The GNU Hurd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2, or (at + published by the Free Software Foundation; either version 3, or (at your option) any later version. The GNU Hurd is distributed in the hope that it will be useful, but @@ -58,6 +58,15 @@ loader_get_memory_desc (l4_word_t nr) return &memory_map[nr]; } +static void +rootserver_relocate (const char *name, + l4_word_t start, l4_word_t end, l4_word_t new_start, + void *cookie) +{ + l4_rootserver_t *s = cookie; + s->low = new_start; + s->high = new_start + (end - start); +} /* Load the ELF images of the kernel and the initial servers into memory, checking for overlaps. Update the start and end @@ -66,21 +75,29 @@ loader_get_memory_desc (l4_word_t nr) static void load_components (void) { + /* Make sure that the required components are available and mark the + memory their packed images occupy as used. */ if (!kernel.low) panic ("No L4 kernel found"); - loader_add_region ("kernel-mod", kernel.low, kernel.high); + loader_add_region ("kernel-mod", kernel.low, kernel.high, + rootserver_relocate, &kernel); if (!sigma0.low) panic ("No sigma0 server found"); - loader_add_region ("sigma0-mod", sigma0.low, sigma0.high); + loader_add_region ("sigma0-mod", sigma0.low, sigma0.high, + rootserver_relocate, &sigma0); - if (sigma1.low) - loader_add_region ("sigma1-mod", sigma1.low, sigma1.high); + if (sigma1.low) + loader_add_region ("sigma1-mod", sigma1.low, sigma1.high, + rootserver_relocate, &sigma1); if (!rootserver.low) panic ("No rootserver server found"); - loader_add_region ("rootserver-mod", rootserver.low, rootserver.high); + loader_add_region ("rootserver-mod", rootserver.low, rootserver.high, + rootserver_relocate, &rootserver); + /* Since we did not panic, there are no conflicts and we can now + unpack the images. */ loader_elf_load ("kernel", kernel.low, kernel.high, &kernel.low, &kernel.high, &kernel.ip); loader_remove_region ("kernel-mod"); diff --git a/laden/loader.c b/laden/loader.c index bab5bab..5524bd9 100644 --- a/laden/loader.c +++ b/laden/loader.c @@ -1,12 +1,12 @@ /* loader.c - Load ELF files. - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2003, 2007 Free Software Foundation, Inc. Written by Marcus Brinkmann. This file is part of the GNU Hurd. The GNU Hurd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2, or (at + published by the Free Software Foundation; either version 3, or (at your option) any later version. The GNU Hurd is distributed in the hope that it will be useful, but @@ -25,14 +25,13 @@ #include #include +#include "laden.h" #include "loader.h" #include "output.h" #include "shutdown.h" #include "elf.h" - - /* Verify that the memory region START to END (exclusive) is valid. */ static void mem_check (const char *name, l4_word_t start, l4_word_t end) @@ -107,52 +106,157 @@ static struct const char *name; l4_word_t start; l4_word_t end; + /* Function pointer to relocate this region in case of conflict. */ + relocate_region rr; + void *cookie; + + /* If this descriptor is valid. */ + int used; } used_regions[MAX_REGIONS]; static int nr_regions; -/* Check that the region with the name NAME from START to END does not - overlap with an existing region. */ -static void -check_region (const char *name, l4_word_t start, l4_word_t end) -{ - int i; - - mem_check (name, start, end); - - for (i = 0; i < nr_regions; i++) - { - if ((start >= used_regions[i].start && start < used_regions[i].end) - || (end >= used_regions[i].start && end <= used_regions[i].end) - || (start < used_regions[i].start && end > used_regions[i].start)) - panic ("%s (0x%x - 0x%x) conflicts with %s (0x%x - 0x%x)", - name, start, end, used_regions[i].name, used_regions[i].start, - used_regions[i].end); - } -} - - /* Add the region with the name NAME from START to END to the table of regions to check against. Before doing that, check for overlaps with existing regions. */ void -loader_add_region (const char *name, l4_word_t start, l4_word_t end) +loader_add_region (const char *name, l4_word_t start, l4_word_t end, + relocate_region rr, void *cookie) { debug ("Protected Region: %s (0x%x - 0x%x)\n", name, start, end); - if (nr_regions == MAX_REGIONS) - panic ("Too many memory regions, region %s doesn't fit", name); - if (start >= end) panic ("Region %s has a start address following the end address", name); - check_region (name, start, end); + /* Make sure that the requested region corresponds to real + memory. */ + mem_check (name, start, end); + + /* Allocate a region descriptor. */ + int region = nr_regions; + if (region == MAX_REGIONS) + { + for (region = 0; region < MAX_REGIONS; region ++) + if (! used_regions[region].used) + break; + + if (region == MAX_REGIONS) + panic ("Out of memory region descriptors, region %s doesn't fit", + name); + } + else + nr_regions ++; + + used_regions[region].name = name; + used_regions[region].start = start; + used_regions[region].end = end; + used_regions[region].rr = rr; + used_regions[region].cookie = cookie; + used_regions[region].used = 1; - used_regions[nr_regions].name = name; - used_regions[nr_regions].start = start; - used_regions[nr_regions].end = end; - nr_regions++; + /* Check if the region overlaps with any established regions. */ + int i; + for (i = 0; i < nr_regions; i++) + if (i != region + && used_regions[i].used + && ((start >= used_regions[i].start && start < used_regions[i].end) + || (end >= used_regions[i].start && end <= used_regions[i].end) + || (start < used_regions[i].start && end > used_regions[i].start))) + /* Region REGION conflict with region I. Try to relocate region + I. */ + { + l4_word_t mstart = used_regions[i].start; + l4_word_t mend = used_regions[i].end; + l4_word_t msize = mend - mstart + 1; + + if (! used_regions[i].rr) + /* Region I is not relocatable. */ + panic ("%s (0x%x - 0x%x) conflicts with %s (0x%x - 0x%x)", + used_regions[region].name, start, end, + used_regions[i].name, mstart, mend); + + debug ("%s (0x%x - 0x%x) conflicts with %s (0x%x - 0x%x);" + " moving latter\n", + used_regions[region].name, start, end, + used_regions[i].name, mstart, mend); + + int j; + for (j = 0; j < loader_get_num_memory_desc (); j ++) + { + l4_memory_desc_t *memdesc = loader_get_memory_desc (j); + l4_word_t mem_low = l4_memory_desc_low (memdesc); + l4_word_t mem_high = l4_memory_desc_high (memdesc); + + printf ("memory_map: %d, %d, 0x%x-0x%x\n", + j, memory_map[j].type, mem_low, mem_high); + if (memory_map[j].type == L4_MEMDESC_CONVENTIONAL + && mem_high - mem_low >= msize) + /* This memory map is useable and large enough. See if + there is a non-conflicting, contiguous space of SIZE + bytes. */ + { + debug ("Considering memory (0x%x-0x%x)\n", + mem_low, mem_high); + + /* Start with the lowest address. */ + l4_word_t ns = mem_low; + + /* See if any regions overlap with (NS, NS + SIZE]. If + so, advance NS just beyond them. */ + int k; + restart: + for (k = 0; + k < nr_regions && ns + msize - 1 <= mem_high; + k ++) + if (used_regions[k].used && k != i + && ((ns >= used_regions[k].start + && ns <= used_regions[k].end) + || (ns + msize - 1 >= used_regions[k].start + && ns + msize - 1 <= used_regions[k].end) + || (ns < used_regions[k].start + && ns + msize - 1 >= used_regions[k].start))) + /* There is overlap, take the end of the conflicting + region as our new start and restart. */ + { + debug ("Can't use 0x%x, %s(0x%x-0x%x) in way\n", + ns, used_regions[k].name, + used_regions[k].start, used_regions[k].end); + ns = used_regions[k].end + 1; + debug ("Trying address 0x%x\n", ns); + goto restart; + } + + if (k == nr_regions && ns + msize - 1 <= mem_high) + /* NS is a good new start! */ + { + printf ("Moving %s(%d) from 0x%x-0x%x to 0x%x-0x%x\n", + used_regions[i].name, i, + used_regions[i].start, used_regions[i].end, + ns, ns + msize - 1); + + memmove ((void *) ns, (void *) used_regions[i].start, + msize); + used_regions[i].start = ns; + used_regions[i].end = ns + msize - 1; + used_regions[i].rr (used_regions[i].name, + used_regions[i].start, + used_regions[i].end, + ns, used_regions[i].cookie); + break; + } + } + } + + if (j == memory_map_size) + /* Couldn't find a free region! */ + panic ("%s (0x%x - 0x%x) conflicts with %s (0x%x - 0x%x)" + " but nowhere to move the latter", + used_regions[region].name, + used_regions[region].start, used_regions[region].end, + used_regions[i].name, + used_regions[i].start, used_regions[i].end); + } } @@ -169,12 +273,7 @@ loader_remove_region (const char *name) if (i == nr_regions) panic ("Assertion failure: Could not find region %s for removal", name); - while (i < nr_regions - 1) - { - used_regions[i] = used_regions[i + 1]; - i++; - } - nr_regions--; + used_regions[i].used = 0; } @@ -296,14 +395,19 @@ loader_elf_load (const char *name, l4_word_t start, l4_word_t end, if (elf->e_machine != elf_machine) panic ("%s is not for this architecture", name); + /* Determine the bounds of the extracted executable. */ for (i = 0; i < elf->e_phnum; i++) { Elf32_Phdr *ph = (Elf32_Phdr *) (start + elf->e_phoff + i * elf->e_phentsize); if (ph->p_type == PT_LOAD) { - check_region (name, ph->p_paddr, - ph->p_paddr + ph->p_offset + ph->p_memsz); + /* FIXME: Add this as a bootloader specific memory type to L4's + memdesc list instead. */ + /* Add the region. */ + loader_add_region (name, ph->p_paddr, ph->p_paddr + ph->p_memsz - 1, + NULL, NULL); + memcpy ((char *) ph->p_paddr, (char *) start + ph->p_offset, ph->p_filesz); /* Initialize the rest. */ @@ -317,10 +421,6 @@ loader_elf_load (const char *name, l4_word_t start, l4_word_t end, } } - /* FIXME: Add this as a bootloader specific memory type to L4's - memdesc list instead. */ - loader_add_region (name, new_start, new_end); - if (new_start_p) *new_start_p = new_start; if (new_end_p) diff --git a/laden/loader.h b/laden/loader.h index 647d78f..129c4ff 100644 --- a/laden/loader.h +++ b/laden/loader.h @@ -1,12 +1,12 @@ /* loader.h - Load ELF binary images, interfaces. - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2003, 2007 Free Software Foundation, Inc. Written by Marcus Brinkmann. This file is part of the GNU Hurd. The GNU Hurd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2, or (at + published by the Free Software Foundation; either version 3, or (at your option) any later version. The GNU Hurd is distributed in the hope that it will be useful, but @@ -35,10 +35,22 @@ l4_word_t loader_get_num_memory_desc (void); l4_memory_desc_t *loader_get_memory_desc (l4_word_t nr); +/* Callback passed to loader_add_region. The region named NAME + starting at START and continuing until END (exclusive) has been + relocated to NEW_START. Update any data structures + appropriately. */ +typedef void (*relocate_region) (const char *name, + l4_word_t start, l4_word_t end, + l4_word_t new_start, + void *cookie); + /* Add the region with the name NAME from START to END to the table of regions to check against. Before doing that, check for overlaps - with existing regions. */ -void loader_add_region (const char *name, l4_word_t start, l4_word_t end); + with existing regions. If at some time an overlap is detected and + RR is not NULL, the region may be relocated. In this case RR is + invoked providing for the possibility to update any pointers. */ +void loader_add_region (const char *name, l4_word_t start, l4_word_t end, + relocate_region rr, void *cookie); /* Remove the region with the name NAME from the table. */ void loader_remove_region (const char *name); -- cgit v1.2.3