diff options
author | marcus <marcus> | 2003-09-16 19:24:05 +0000 |
---|---|---|
committer | marcus <marcus> | 2003-09-16 19:24:05 +0000 |
commit | 5ff04a84d15e866dcb968dace7c231f81d4004b8 (patch) | |
tree | e432af6110042a6b9d12c899dcf1d822ffc9d7af | |
parent | d857a01ad080c376088d206c632304b02b4963c5 (diff) |
Update code to do better memory management, add sigma0 patch to README.
-rw-r--r-- | README | 56 | ||||
-rw-r--r-- | wortel/Makefile.am | 1 | ||||
-rw-r--r-- | wortel/loader.c | 53 | ||||
-rw-r--r-- | wortel/loader.h | 5 | ||||
-rw-r--r-- | wortel/sigma0.c | 144 | ||||
-rw-r--r-- | wortel/sigma0.h | 42 | ||||
-rw-r--r-- | wortel/wortel.c | 175 |
7 files changed, 378 insertions, 98 deletions
@@ -24,11 +24,57 @@ $ cp physmem/physmem /l4/boot Note that use of optimization is mandatory, not optional. -You also need the L4 kernel and sigma0. sigma0 must be built with a -different link base than the default value 0x20000, because that -conflicts with GRUB (on ia32). I have successfully used a link base -of 0x40000. Then set up GRUB to boot laden as the kernel, and the L4 -kernel, sigma0, wortel (the rootserver) and physmem as its modules. + +Installation +------------ + +Prerequisites: Pistachio-0.2 with the patch you can find at the end of +this file. + +Furthermore, sigma0 must be built with a different link base than the +default value 0x20000, because that conflicts with GRUB (on ia32). I +have successfully used a link base of 0x40000. + +Then set up GRUB to boot laden as the kernel, and the L4 kernel, +sigma0, wortel (the rootserver) and physmem as its modules. Try the debug option (-D) to laden and wortel to see some output from them. They are silent by default. + + +sigma0 Patch +------------ + +sigma0 in pistachio 0.2 is a bit buggy. The following patch fixes the +problems that the bugs cause to wortel. + +--- pistachio-0.2/user/serv/sigma0/sigma0.cc.prev 2003-09-16 20:29:14.000000000 +0200 ++++ pistachio-0.2/user/serv/sigma0/sigma0.cc 2003-09-16 21:03:09.000000000 +0200 +@@ -506,7 +506,8 @@ + L4_Word_t low_a = (low + size - 1) & ~(size-1); + L4_Fpage_t ret; + +- if ((high_a - low_a) < size || (owner != tid && owner != L4_anythread)) ++ if (low_a > high_a || (high_a - low_a) < size ++ || (owner != tid && owner != L4_anythread)) + { + // Allocation failed + ret = L4_Nilpage; +@@ -530,7 +531,7 @@ + { + // Allocate from middle of region + ret = L4_FpageLog2 (low_a, log2size) + L4_FullyAccessible; +- memregion_t * r = new memregion_t (high_a, high, owner); ++ memregion_t * r = new memregion_t (low_a + size, high, owner); + r->next = next; + r->prev = this; + r->next->prev = next = r; +@@ -1246,7 +1247,7 @@ + { + if ((fp = r->allocate (log2size)).raw != L4_Nilpage.raw) + { +- map = L4_MapItem (fp, 0); ++ map = L4_MapItem (fp, L4_Address (fp)); + alloc_pool.insert + (new memregion_t (L4_Address (fp), L4_Address (fp) + + (1UL << log2size), tid)); diff --git a/wortel/Makefile.am b/wortel/Makefile.am index 05d0743..48d8f72 100644 --- a/wortel/Makefile.am +++ b/wortel/Makefile.am @@ -32,6 +32,7 @@ wortel_SOURCES = $(ARCH_SOURCES) \ shutdown.h shutdown.c \ elf.h loader.h loader.c \ getpagesize.c \ + sigma0.h sigma0.c \ wortel.h wortel.c /* FIXME: Make linkbase configurable. */ diff --git a/wortel/loader.c b/wortel/loader.c index a66b015..f2a6cf9 100644 --- a/wortel/loader.c +++ b/wortel/loader.c @@ -158,6 +158,59 @@ loader_remove_region (const char *name) } +/* Get the memory range to which the ELF image from START to END + (exclusive) will be loaded. NAME is used for panic messages. */ +void +loader_elf_dest (const char *name, l4_word_t start, l4_word_t end, + l4_word_t *new_start_p, l4_word_t *new_end_p) +{ + l4_word_t new_start = -1; + l4_word_t new_end = 0; + int i; + + Elf32_Ehdr *elf = (Elf32_Ehdr *) start; + + if (elf->e_ident[EI_MAG0] != ELFMAG0 + || elf->e_ident[EI_MAG1] != ELFMAG1 + || elf->e_ident[EI_MAG2] != ELFMAG2 + || elf->e_ident[EI_MAG3] != ELFMAG3) + panic ("%s is not an ELF file", name); + + if (elf->e_type != ET_EXEC) + panic ("%s is not an executable file", name); + + if (!elf->e_phoff) + panic ("%s has no valid program header offset", name); + +#ifdef i386 + if (elf->e_ident[EI_CLASS] != ELFCLASS32 + || elf->e_ident[EI_DATA] != ELFDATA2LSB + || elf->e_machine != EM_386) + panic ("%s is not for this architecture", name); +#else +#error Not ported to this architecture! +#endif + + 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) + { + if (ph->p_paddr < new_start) + new_start = ph->p_paddr; + if (ph->p_memsz + ph->p_paddr > new_end) + new_end = ph->p_memsz + ph->p_paddr; + } + } + + if (new_start_p) + *new_start_p = new_start; + if (new_end_p) + *new_end_p = new_end; +} + + /* Load the ELF image from START to END (exclusive) into memory under the name NAME (also used as the name for the region of the resulting ELF program). Return the lowest and highest address used diff --git a/wortel/loader.h b/wortel/loader.h index d9c310b..0ceb7f8 100644 --- a/wortel/loader.h +++ b/wortel/loader.h @@ -43,6 +43,11 @@ void loader_add_region (const char *name, l4_word_t start, l4_word_t end); /* Remove the region with the name NAME from the table. */ void loader_remove_region (const char *name); +/* Get the memory range to which the ELF image from START to END + (exclusive) will be loaded. NAME is used for panic messages. */ +void loader_elf_dest (const char *name, l4_word_t start, l4_word_t end, + l4_word_t *new_start_p, l4_word_t *new_end_p); + /* Load the ELF image from START to END into memory under the name NAME (also used as the name for the region of the resulting ELF program). Return the lowest and highest address used by the diff --git a/wortel/sigma0.c b/wortel/sigma0.c new file mode 100644 index 0000000..84cacc5 --- /dev/null +++ b/wortel/sigma0.c @@ -0,0 +1,144 @@ +/* Client code for sigma0. + Copyright (C) 2003 Free Software Foundation, Inc. + 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 Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#include <l4.h> + +#include "shutdown.h" + +/* The thread ID of sigma0. */ +#define SIGMA0_TID (l4_global_id (l4_thread_user_base (), 1)) + +/* The message label for the sigma0 request page operation. This is + -6 in the upper 24 bits. */ +#define SIGMA0_RPC (0xffa0) + +/* The message label for undocumented sigma0 operations. This is + -1001 in the upper 24 bits. */ +#define SIGMA0_EXT (0xc170) + +/* For undocumented operations, this is the meaning of the first + untyped word in the message (MR1). */ +#define SIGMA0_EXT_SET_VERBOSITY 1 +#define SIGMA0_EXT_DUMP_MEMORY 2 + +/* Set the verbosity level in sigma0. The only levels used currently + are 1 to 3. Returns 0 on success, otherwise an IPC error code. */ +void +sigma0_set_verbosity (l4_word_t level) +{ + l4_msg_t msg; + l4_msg_tag_t tag; + + l4_msg_clear (&msg); + l4_set_msg_label (&msg, SIGMA0_EXT); + l4_msg_append_word (&msg, SIGMA0_EXT_SET_VERBOSITY); + l4_msg_append_word (&msg, level); + l4_msg_load (&msg); + tag = l4_send (SIGMA0_TID); + if (l4_ipc_failed (tag)) + panic ("%s: request failed during %s: %u", __func__, + l4_error_code () & 1 ? "receive" : "send", + (l4_error_code () >> 1) & 0x7); +} + + +/* Request a memory dump from sigma0. If WAIT is true, wait until the + dump is completed before continuing. */ +void +sigma0_dump_memory (int wait) +{ + l4_msg_t msg; + l4_msg_tag_t tag; + + l4_msg_clear (&msg); + l4_set_msg_label (&msg, SIGMA0_EXT); + l4_msg_append_word (&msg, SIGMA0_EXT_DUMP_MEMORY); + l4_msg_append_word (&msg, wait); + l4_msg_load (&msg); + if (wait) + tag = l4_call (SIGMA0_TID); + else + tag = l4_send (SIGMA0_TID); + if (l4_ipc_failed (tag)) + panic ("%s: request failed during %s: %u", __func__, + l4_error_code () & 1 ? "receive" : "send", + (l4_error_code () >> 1) & 0x7); +} + + +/* Request the fpage FPAGE from sigma0. */ +void +sigma0_get_fpage (l4_fpage_t fpage) +{ + l4_msg_t msg; + l4_msg_tag_t tag; + l4_map_item_t map_item; + + l4_accept (l4_map_grant_items (l4_complete_address_space)); + l4_msg_clear (&msg); + l4_set_msg_label (&msg, SIGMA0_RPC); + l4_msg_append_word (&msg, fpage.raw); + l4_msg_append_word (&msg, L4_DEFAULT_MEMORY); + l4_msg_load (&msg); + tag = l4_call (SIGMA0_TID); + if (l4_ipc_failed (tag)) + panic ("%s: request failed during %s: %u", __func__, + l4_error_code () & 1 ? "receive" : "send", + (l4_error_code () >> 1) & 0x7); + if (l4_untyped_words (tag) != 0 || l4_typed_words (tag) != 2) + panic ("%s: invalid format of sigma0 reply", __func__); + l4_msg_store (tag, &msg); + l4_msg_get_map_item (&msg, 0, &map_item); + if (l4_is_nil_fpage (map_item.send_fpage)) + panic ("%s: sigma0 rejected mapping", __func__); +} + + +/* Request an fpage of the size 2^SIZE from sigma0. The fpage will be + fullly accessible. */ +l4_fpage_t +sigma0_get_any (unsigned int size) +{ + l4_msg_t msg; + l4_msg_tag_t tag; + l4_map_item_t map_item; + l4_fpage_t fpage = l4_fpage_log2 (-1, size); + + l4_accept (l4_map_grant_items (l4_complete_address_space)); + l4_msg_clear (&msg); + l4_set_msg_label (&msg, SIGMA0_RPC); + l4_msg_append_word (&msg, fpage.raw); + l4_msg_append_word (&msg, L4_DEFAULT_MEMORY); + l4_msg_load (&msg); + tag = l4_call (SIGMA0_TID); + if (l4_ipc_failed (tag)) + panic ("%s: request failed during %s: %u", __func__, + l4_error_code () & 1 ? "receive" : "send", + (l4_error_code () >> 1) & 0x7); + if (l4_untyped_words (tag) != 0 + || l4_typed_words (tag) != 2) + panic ("%s: invalid format of sigma0 reply", __func__); + l4_msg_store (tag, &msg); + l4_msg_get_map_item (&msg, 0, &map_item); + return map_item.send_fpage; +} diff --git a/wortel/sigma0.h b/wortel/sigma0.h new file mode 100644 index 0000000..4c234cb --- /dev/null +++ b/wortel/sigma0.h @@ -0,0 +1,42 @@ +/* Client code for sigma0. + Copyright (C) 2003 Free Software Foundation, Inc. + 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 Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#include <l4.h> + +/* Set the verbosity level in sigma0. The only levels used currently + are 1 to 3. Returns 0 on success, otherwise an IPC error code. */ +void sigma0_set_verbosity (l4_word_t level); + + +/* Request a memory dump from sigma0. If WAIT is true, wait until the + dump is completed before continuing. */ +void sigma0_dump_memory (int wait); + + +/* Request the fpage FPAGE from sigma0. */ +void sigma0_get_fpage (l4_fpage_t fpage); + + +/* Request an fpage of the size 2^SIZE from sigma0. The fpage will be + fullly accessible. */ +l4_fpage_t sigma0_get_any (unsigned int size); diff --git a/wortel/wortel.c b/wortel/wortel.c index 331a265..7101f46 100644 --- a/wortel/wortel.c +++ b/wortel/wortel.c @@ -25,6 +25,7 @@ #include <alloca.h> #include "wortel.h" +#include "sigma0.h" /* The program name. */ @@ -35,6 +36,15 @@ l4_word_t wortel_start; l4_word_t wortel_end; +/* Unused memory. These fpages mark memory which we needed at some + time, but don't need anymore. It can be granted to the physical + memory server at startup. This includes architecture dependent + boot data as well as the physical memory server module. */ +#define MAX_UNUSED_FPAGES 32 +l4_fpage_t wortel_unused_fpages[MAX_UNUSED_FPAGES]; +unsigned int wortel_unused_fpages_count; + + /* Room for the arguments. 1 KB is a cramped half-screen full, which should be more than enough. */ char mods_args[1024]; @@ -140,65 +150,6 @@ make_fpages (l4_word_t start, l4_word_t end, l4_fpage_t *fpages) } -/* Request the fpage FPAGE from sigma0. */ -static void -sigma0_get_fpage (l4_fpage_t fpage) -{ - l4_msg_t msg; - l4_msg_tag_t msg_tag; - l4_map_item_t map_item; - - l4_accept (l4_map_grant_items (l4_complete_address_space)); - l4_msg_clear (&msg); - l4_set_msg_label (&msg, 0xffa0); - l4_msg_append_word (&msg, fpage.raw); - l4_msg_append_word (&msg, L4_DEFAULT_MEMORY); - l4_msg_load (&msg); - msg_tag = l4_call (l4_global_id (l4_thread_user_base (), 1)); - if (l4_ipc_failed (msg_tag)) - panic ("sigma0 request failed during %s: %u", - l4_error_code () & 1 ? "receive" : "send", - (l4_error_code () >> 1) & 0x7); - if (l4_untyped_words (msg_tag) != 0 - || l4_typed_words (msg_tag) != 2) - panic ("Invalid format of sigma0 reply"); - l4_msg_store (msg_tag, &msg); - l4_msg_get_map_item (&msg, 0, &map_item); - if (map_item.send_fpage.raw == l4_nilpage.raw) - panic ("sigma0 rejected mapping"); -} - -/* Request an fpage of the size 2^SIZE from sigma0. */ -static l4_fpage_t -sigma0_get_any (unsigned int size) -{ - l4_msg_t msg; - l4_msg_tag_t msg_tag; - l4_map_item_t map_item; - l4_fpage_t fpage = l4_fpage_add_rights (l4_fpage_log2 (-1, size), - l4_fully_accessible); - - l4_accept (l4_map_grant_items (l4_complete_address_space)); - l4_msg_clear (&msg); - l4_set_msg_label (&msg, 0xffa0); - debug ("Request 0x%x\n", fpage.raw); - l4_msg_append_word (&msg, fpage.raw); - l4_msg_append_word (&msg, L4_DEFAULT_MEMORY); - l4_msg_load (&msg); - msg_tag = l4_call (l4_global_id (l4_thread_user_base (), 1)); - if (l4_ipc_failed (msg_tag)) - panic ("sigma0 request failed during %s: %u", - l4_error_code () & 1 ? "receive" : "send", - (l4_error_code () >> 1) & 0x7); - if (l4_untyped_words (msg_tag) != 0 - || l4_typed_words (msg_tag) != 2) - panic ("Invalid format of sigma0 reply"); - l4_msg_store (msg_tag, &msg); - l4_msg_get_map_item (&msg, 0, &map_item); - debug ("Got 0x%x\n", map_item.send_fpage.raw); - return map_item.send_fpage; -} - static void load_components (void) @@ -207,57 +158,82 @@ load_components (void) unsigned int nr_fpages; l4_word_t min_page_size = getpagesize (); unsigned int i; + l4_word_t addr; + l4_word_t end_addr; /* One issue we have to solve is to make sure that when the physical - memory server requests all the available physical pages, we know - which pages we can give to it, and which we can't. This can be - left to sigma0, as long as we request all pages from sigma0 we + memory server requests all the available physical fpages, we know + which fpages we can give to it, and which we can't. This can be + left to sigma0, as long as we request all fpages from sigma0 we can't give to the physical memory server up-front. We do this in several steps: First, we copy all of the startup information to memory that is part of the wortel binary image - itself. This is done by the architecture dependant + itself. This is done by the architecture dependent find_components function. Then we request all of our own memory, - and all the memory needed for the physical memory server image - (at its destination address), and all the memory for each module - (at their corresponding load addresses). */ + all the memory for our modules, and finally all the memory needed + for the physical memory server image (at its destination + address). */ if (wortel_start & (min_page_size - 1)) panic ("%s does not start on a page boundary", program_name); loader_add_region (program_name, wortel_start, wortel_end); - nr_fpages = make_fpages (wortel_start, wortel_end, fpages); - while (nr_fpages--) - sigma0_get_fpage (fpages[nr_fpages]); + + /* We must request our own memory using the smallest fpages + possible, because we already have some memory mapped due to page + faults, and fpages are specified as inseparable objects. */ + for (addr = wortel_start; addr < wortel_end; addr += min_page_size) + sigma0_get_fpage (l4_fpage (addr, min_page_size)); /* First protect all pages covered by the modules. This will also - show if each module starts (and ends) on its own page. */ + show if each module starts (and ends) on its own page. Request + all memory for all modules. Although we can release the memory + for the physmem module later on, we have to touch it anyway to + load it to its destination address, and requesting the fpages now + allows us to choose how we want to split up the module in + (inseparable) fpages. */ for (i = 0; i < mods_count; i++) { if (mods[i].start & (min_page_size - 1)) panic ("Module %s does not start on a page boundary", mods[i].name); loader_add_region (mods[i].name, mods[i].start, mods[i].end); + + nr_fpages = make_fpages (mods[i].start, mods[i].end, fpages); + if (i == MOD_PHYSMEM) + { + /* The physical memory server module memory can be recycled + later. */ + if (nr_fpages + wortel_unused_fpages_count > MAX_UNUSED_FPAGES) + panic ("not enough room in unused fpages list for physmem-mod"); + memcpy (&wortel_unused_fpages[wortel_unused_fpages_count], + fpages, sizeof (l4_fpage_t) * nr_fpages); + wortel_unused_fpages_count += nr_fpages; + } + + while (nr_fpages--) + sigma0_get_fpage (fpages[nr_fpages]); } + /* Because loading the physical memory server to its destination + address will touch the destination memory, which we later want to + grant to the physical memory server using (inseparable) fpages, + we request the desired fpages up-front. */ + loader_elf_dest ("physmem-server", mods[MOD_PHYSMEM].start, + mods[MOD_PHYSMEM].end, &addr, &end_addr); + nr_fpages = make_fpages (addr, end_addr, fpages); + while (nr_fpages--) + sigma0_get_fpage (fpages[nr_fpages]); + /* Now load the physical memory server to its destination address. */ - if (!mods[MOD_PHYSMEM].start) + addr = mods[MOD_PHYSMEM].start; + end_addr = mods[MOD_PHYSMEM].end; + if (!addr) panic ("No physical memory server found"); - loader_elf_load ("physmem-server", mods[MOD_PHYSMEM].start, - mods[MOD_PHYSMEM].end, + loader_elf_load ("physmem-server", addr, end_addr, &mods[MOD_PHYSMEM].start, &mods[MOD_PHYSMEM].end, &mods[MOD_PHYSMEM].ip); loader_remove_region ("physmem-mod"); - - /* Finally we can request all the memory for the physical memory - server and all other modules from sigma0. This will register the - memory as taken by us, and the memory will not be returned by any - future request. */ - for (i = 0; i < mods_count; i++) - { - nr_fpages = make_fpages (mods[i].start, mods[i].end, fpages); - while (nr_fpages--) - sigma0_get_fpage (fpages[nr_fpages]); - } } @@ -276,7 +252,6 @@ start_components (void) || mods[MOD_PHYSMEM].ip > mods[MOD_PHYSMEM].end) panic ("physmem has invalid IP"); - cap_id = wortel_add_user (2); /* FIXME: Pass cap_id to physmem. */ /* Thread nr is next available after rootserver thread nr, @@ -393,8 +368,12 @@ serve_bootstrap_requests (void) /* The size of the region that we are currently trying to allocate for GET_MEM requests. If this is smaller than 2^10, no more memory is available. */ - unsigned int get_mem_size = 12; + unsigned int get_mem_size = sizeof (l4_word_t) * 8 - 1; + while (get_mem_size >= 10 + && ! ((1 << get_mem_size) & l4_page_size_mask ())) + get_mem_size--; + do { l4_thread_id_t from; @@ -438,13 +417,23 @@ serve_bootstrap_requests (void) if (get_mem_size < 10) panic ("physmem server does not stop requesting memory"); - do - { - fpage = sigma0_get_any (get_mem_size); - if (fpage.raw == l4_nilpage.raw) - get_mem_size--; - } - while (fpage.raw == l4_nilpage.raw && get_mem_size >= 10); + /* Give out the memory. First our unused fpages, then the + fpages we can get from sigma0. */ + if (wortel_unused_fpages_count) + fpage = wortel_unused_fpages[--wortel_unused_fpages_count]; + else + do + { + fpage = sigma0_get_any (get_mem_size); + if (fpage.raw == l4_nilpage.raw) + { + get_mem_size--; + while (get_mem_size >= 10 + && ! ((1 << get_mem_size) & l4_page_size_mask ())) + get_mem_size--; + } + } + while (fpage.raw == l4_nilpage.raw && get_mem_size >= 10); grant_item = l4_grant_item (fpage, l4_address (fpage)); l4_msg_clear (&msg); |