summaryrefslogtreecommitdiff
path: root/viengoos/memory.c
diff options
context:
space:
mode:
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);
+}