summaryrefslogtreecommitdiff
path: root/viengoos/memory.c
diff options
context:
space:
mode:
authorneal <neal>2007-11-16 13:35:00 +0000
committerneal <neal>2007-11-16 13:35:00 +0000
commite46ff816c662bc8b47dfc00bbe5501dbeffd93bb (patch)
tree16603b813cf7301b85b58f28217aa188825513d8 /viengoos/memory.c
parent17b21c229fe9756a2e9ec158b6bdf5c2ca9869a5 (diff)
2007-11-16 Neal H. Walfield <neal@gnu.org>
* viengoos/Makefile.am: New file based on ../wortel/Makefile.am. * viengoos/headers.m4: New file. * viengoos/config.m4: New file based on ../wortel/config.m4. * viengoos/viengoos.h: New file. * viengoos/viengoos.c: New file. * viengoos/activity.h: Likewise. * viengoos/activity.c: Likewise. * viengoos/as.h: Likewise. * viengoos/as.c: Likewise. * viengoos/cap-lookup.c: Likewise. * viengoos/cap.h: Likewise. * viengoos/cap.c: Likewise. * viengoos/thread.h: New file. * viengoos/thread.c: New file. * viengoos/object.h: New file. * viengoos/object.c: New file. * viengoos/rm.h: New file. * viengoos/server.c: New file. * viengoos/server.h: New file. * viengoos/zalloc.h: Copied from ../physmem. * viengoos/zalloc.c: Copied from ../physmem. Don't include "output.h". Include <hurd/stddef.h>. Change uses of min_page_size to PAGESIZE. * viengoos/memory.h: New file. * viengoos/memory.c: New file. * viengoos/sigma0.c: Copy from ../wortel. * viengoos/sigma0.h: Copy from ../wortel. Don't include "shutdown.h". Include <hurd/stddef.h>. * viengoos/bits.h: Likewise. * viengoos/panic.c: New file. * viengoos/debug.c: Likewise. * viengoos/debug.h: Likewise. * viengoos/boot-modules.h: Likewise. * viengoos/boot-modules.c: Likewise. * viengoos/elf.h: Copied from ../wortel. * viengoos/loader.c: New file based on ../wortel/loader.c. * viengoos/loader.h: New file. * viengoos/multiboot.h: Copied from Grub. * viengoos/mmap.c: New file based on ../physmem/mmap.c. * viengoos/malloc-wrap.c: New file based on ../physmem/malloc-wrap.c. * viengoos/malloc.c: Version 2.8.3 of Doug Lea's malloc.c. * viengoos/malloc.h: Version 2.8.3 of Doug Lea's malloc.h. * viengoos/ia32-cmain.c: New file based on ../wortel/ia32-cmain.c. * viengoos/ia32-crt0.S: Copied from ../wortel. (STACK_SIZE): Use a 16 page stack. * viengoos/ia32-output.c: Copied from ../wortel. * viengoos/ia32-shutdown.c: Likewise. * viengoos/output.h: New file based on ../wortel/output.h. Include <stdarg.h>. (cprintf): New definition. (output_debug): Don't define. (debug): Don't define. * viengoos/output.c: New file based on ../wortel/output.c. Don't include <stdlib.h>. (vprintf): New function. (printf): Implement in terms of vprintf. * viengoos/output-none.c: Copied from ../wortel. * viengoos/output-serial.c: Likewise. * viengoos/output-stdio.c: New file. * viengoos/output-vga.c: Copied from ../wortel. * viengoos/shutdown.h: New file based on ../wortel/shutdown.h. Don't include "output.h". (panic): Don't define. (shutdown): Rename from this... (shutdown_machine): ... to this. * viengoos/shutdown.c: New file based on ../wortel/shutdown.c. (reset) [_L4_TEST_ENVIRONMENT]: Call abort. (halt) [_L4_TEST_ENVIRONMENT]: Call abort. (shutdown): Rename from this... (shutdown_machine): ... to this. * viengoos/t-environment.h: New file based on ../libl4/tests/environment.h. Protect from multiple inclusion. Include <hurd/stddef.h>. Include <string.h>. Include <l4/stubs.h>. (program_name): New declaration. (check_nr): Don't assume that val1 and val2 are _L4_word_t, use typeof instead. (main): Call output_init. * viengoos/t-as.c: New file.
Diffstat (limited to 'viengoos/memory.c')
-rw-r--r--viengoos/memory.c358
1 files changed, 358 insertions, 0 deletions
diff --git a/viengoos/memory.c b/viengoos/memory.c
new file mode 100644
index 0000000..26ece15
--- /dev/null
+++ b/viengoos/memory.c
@@ -0,0 +1,358 @@
+/* memory.c - Basic memory management routines.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Written by Neal H. Walfield <neal@gnu.org>.
+
+ 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 3 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include "zalloc.h"
+#include "memory.h"
+
+#include <string.h>
+
+#include <l4.h>
+#include <hurd/btree.h>
+#include <hurd/stddef.h>
+
+#ifdef _L4_TEST_ENVIRONMENT
+#include <sys/mman.h>
+#else
+#include "sigma0.h"
+#endif
+
+l4_word_t first_frame;
+l4_word_t last_frame;
+
+struct region
+{
+ l4_word_t start;
+ l4_word_t end;
+};
+
+struct reservation
+{
+ struct region region;
+ enum memory_reservation type;
+ /* If this descriptor is allocated. */
+ int used;
+
+ hurd_btree_node_t node;
+};
+
+#define MAX_RESERVATIONS 128
+static struct reservation reservation_pool[128];
+
+static int
+reservation_node_compare (const struct region *a,
+ const struct region *b)
+{
+ if (a->end < b->start)
+ /* A ends before B starts. */
+ return -1;
+ if (b->end < a->start)
+ /* B ends before A starts. */
+ return 1;
+ /* Overlap. */
+ return 0;
+}
+
+BTREE_CLASS (reservation, struct reservation, struct region, region, node,
+ reservation_node_compare);
+
+static hurd_btree_reservation_t reservations;
+
+bool
+memory_reserve (l4_word_t start, l4_word_t end,
+ enum memory_reservation type)
+{
+ assert (start < end);
+
+ struct region region = { start, end };
+
+ debug (5, "Reserving region 0x%x-0x%x (%d)", start, end, type);
+
+ /* Check for overlap. */
+ struct reservation *overlap
+ = hurd_btree_reservation_find (&reservations, &region);
+ if (overlap)
+ {
+ debug (5, "Region 0x%x-0x%x overlaps with region 0x%x-0x%x",
+ start, end, overlap->region.start, overlap->region.end);
+ return false;
+ }
+
+ /* See if we can coalesce. */
+ region.start --;
+ region.end ++;
+ overlap = hurd_btree_reservation_find (&reservations, &region);
+ if (overlap)
+ {
+ struct reservation *right;
+ struct reservation *left;
+
+ if (overlap->region.start == end + 1)
+ /* OVERLAP starts just after END. */
+ {
+ right = overlap;
+ left = hurd_btree_reservation_prev (overlap);
+ }
+ else
+ /* OVERLAP starts just before START. */
+ {
+ assert (overlap->region.end + 1 == start);
+ left = overlap;
+ right = hurd_btree_reservation_next (overlap);
+ }
+
+ int coalesced = 0;
+
+ if (right->region.start == end + 1
+ && right->type == type)
+ /* We can coalesce with RIGHT. */
+ {
+ debug (5, "Coalescing with region 0x%x-0x%x",
+ right->region.start, right->region.end);
+ right->region.start = start;
+ coalesced = 1;
+ }
+ else
+ right = NULL;
+
+ if (left->region.end + 1 == start
+ && left->type == type)
+ /* We can coalesce with LEFT. */
+ {
+ debug (5, "Coalescing with region 0x%x-0x%x",
+ left->region.start, left->region.end);
+
+ if (right)
+ {
+ /* We coalesce with LEFT and RIGHT. */
+ left->region.end = overlap->region.end;
+
+ /* Deallocate RIGHT. */
+ hurd_btree_reservation_detach (&reservations, right);
+ right->used = 0;
+ }
+ left->region.end = end;
+
+ coalesced = 1;
+ }
+
+ if (coalesced)
+ return true;
+ }
+
+ /* There are no regions with which we can coalesce. Allocate a new
+ descriptor. */
+ int i;
+ for (i = 0; i < MAX_RESERVATIONS; i ++)
+ if (! reservation_pool[i].used)
+ {
+ reservation_pool[i].used = 1;
+ reservation_pool[i].region.start = start;
+ reservation_pool[i].region.end = end;
+ reservation_pool[i].type = type;
+
+ struct reservation *r
+ = hurd_btree_reservation_insert (&reservations,
+ &reservation_pool[i]);
+ if (r)
+ panic ("Error inserting reservation!");
+ return true;
+ }
+
+ panic ("No reservation descriptors available.");
+ return false;
+}
+
+void
+memory_reserve_dump (void)
+{
+ debug (3, "Reserved regions:");
+ struct reservation *r;
+ for (r = hurd_btree_reservation_first (&reservations);
+ r; r = hurd_btree_reservation_next (r))
+ debug (3, " 0x%x-0x%x", r->region.start, r->region.end);
+}
+
+bool
+memory_is_reserved (l4_word_t start, l4_word_t end,
+ l4_word_t *start_reservation,
+ l4_word_t *end_reservation)
+{
+ assert (start < end);
+
+ struct region region = { start, end };
+
+ struct reservation *overlap = hurd_btree_reservation_find (&reservations,
+ &region);
+ if (! overlap)
+ /* No overlap. */
+ return false;
+
+ /* Find the first region that overlaps with REGION. */
+ struct reservation *prev = overlap;
+ do
+ {
+ overlap = prev;
+ prev = hurd_btree_reservation_prev (overlap);
+ }
+ while (prev && prev->region.end > start);
+
+ debug (5, "Region 0x%x-0x%x overlaps with reserved region 0x%x-0x%x",
+ start, end, overlap->region.start, overlap->region.end);
+
+ *start_reservation
+ = overlap->region.start > start ? overlap->region.start : start;
+ *end_reservation = overlap->region.end < end ? overlap->region.end : end;
+ return true;
+}
+
+/* Add the memory starting at byte START and continuing until byte END
+ to the free pool. START must name the first byte in a page and END
+ the last. */
+static void
+memory_add (l4_word_t start, l4_word_t end)
+{
+ assert ((start & (PAGESIZE - 1)) == 0);
+ assert ((end & (PAGESIZE - 1)) == (PAGESIZE - 1));
+
+ debug (5, "Request to add physical memory 0x%x-0x%x", start, end);
+
+ l4_word_t start_reservation;
+ l4_word_t end_reservation;
+
+ while (start < end)
+ {
+ if (! memory_is_reserved (start, end,
+ &start_reservation, &end_reservation))
+ start_reservation = end_reservation = end + 1;
+ else
+ /* Round the start of the reservation down. */
+ {
+ start_reservation &= ~(PAGESIZE - 1);
+ debug (5, "Not adding reserved memory 0x%x-0x%x",
+ start_reservation, end_reservation);
+ }
+
+ if (start_reservation - start > 0)
+ {
+ debug (5, "Adding physical memory 0x%x-0x%x",
+ start, start_reservation - 1);
+ zfree (start, start_reservation - start);
+ }
+
+ /* Set START to first page after the end of the reservation. */
+ start = (end_reservation + PAGESIZE - 1)
+ & ~(PAGESIZE - 1);
+ }
+}
+
+void
+memory_reservation_clear (enum memory_reservation type)
+{
+ struct reservation *r = hurd_btree_reservation_first (&reservations);
+ while (r)
+ {
+ struct reservation *next = hurd_btree_reservation_next (r);
+
+ if (r->type == type)
+ /* We can clear this reserved region. */
+ {
+ hurd_btree_reservation_detach (&reservations, r);
+ r->used = 0;
+
+ memory_add (r->region.start & ~(PAGESIZE - 1),
+ (r->region.end & ~(PAGESIZE - 1))
+ + PAGESIZE - 1);
+ }
+
+ r = next;
+ }
+}
+
+void
+memory_grab (void)
+{
+ bool first = true;
+
+ void add (l4_word_t addr, l4_word_t length)
+ {
+ if (first || addr < first_frame)
+ first_frame = addr;
+ if (first || addr + length - PAGESIZE > last_frame)
+ last_frame = addr + length - PAGESIZE;
+ if (first)
+ first = false;
+
+ memory_add (addr, addr + length - 1);
+ }
+
+#ifdef _L4_TEST_ENVIRONMENT
+ extern char _start;
+ extern char _end;
+
+#define SIZE 8 * 1024 * 1024
+ void *m = mmap (NULL, SIZE, PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ assert_perror (errno);
+ if (m == MAP_FAILED)
+ panic ("No memory: %m");
+ add ((l4_word_t) m, SIZE);
+
+ /* Add binary. */
+ l4_word_t s = (l4_word_t) &_start & ~(PAGESIZE - 1);
+ l4_word_t e = ((((l4_word_t) &_end) + PAGESIZE) & ~(PAGESIZE - 1)) - 1;
+ add (s, e - s + 1);
+
+#else
+ l4_word_t s;
+ l4_fpage_t fpage;
+ /* Try with the largest fpage possible. */
+ for (s = L4_WORDSIZE - 1; s >= l4_min_page_size_log2 (); s --)
+ /* Keep getting pages of size 2^S. */
+ while (! l4_is_nil_fpage (fpage = sigma0_get_any (s)))
+ /* FPAGE is an fpage of size 2^S. Add each non-reserved base
+ frame to the free list. */
+ add (l4_address (fpage), l4_size (fpage));
+#endif
+
+#ifndef NDEBUG
+ do_debug (3)
+ zalloc_dump_zones (__func__);
+#endif
+}
+
+l4_word_t
+memory_frame_allocate (void)
+{
+ l4_word_t f = zalloc (PAGESIZE);
+ memset ((void *) f, 0, PAGESIZE);
+ return f;
+}
+
+void
+memory_frame_free (l4_word_t addr)
+{
+ /* It better be page aligned. */
+ assert ((addr & (PAGESIZE - 1)) == 0);
+ /* It better be memory we know about. */
+ assert (first_frame <= addr);
+ assert (addr <= last_frame);
+
+ zfree (addr, PAGESIZE);
+}