summaryrefslogtreecommitdiff
path: root/laden
diff options
context:
space:
mode:
authorneal <neal>2007-07-25 08:30:04 +0000
committerneal <neal>2007-07-25 08:30:04 +0000
commit02f20279fec373a8b47b4b554fd5dac2e6504fbe (patch)
treed6ccfeec7f4cca02a6431877f1bc7f0b754fb607 /laden
parentc12cc1f2e289e6cad3f89412962bb497ad1f0184 (diff)
2007-07-25 Neal H. Walfield <neal@gnu.org>
* 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.
Diffstat (limited to 'laden')
-rw-r--r--laden/ChangeLog33
-rw-r--r--laden/ia32-cmain.c105
-rw-r--r--laden/laden.c31
-rw-r--r--laden/loader.c192
-rw-r--r--laden/loader.h20
5 files changed, 296 insertions, 85 deletions
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 <neal@gnu.org>
+
+ * laden.h (add_memory_map): Fix indentation.
+
+2007-07-25 Neal H. Walfield <neal@gnu.org>
+
+ * 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 <marcus@gnu.org>
* 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 <string.h>
#include <l4/kip.h>
+#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);