12 /* Page allocator. Hands out memory in page-size chunks.
13 See malloc.h for an allocator that hands out smaller
16 We simply use a linked list of free pages. It would be
17 straightforward to add all available memory to this free list
18 at initialization time. In practice, though, that's really
19 slow because it causes the emulator we're running under to
20 have to fault in every page of memory. So instead we only add
21 pages to the free list as needed. */
23 /* A free page owned by the page allocator. */
26 list_elem free_elem; /* Free list element. */
29 /* Keeps multiple threads away from free_pages and
31 static struct lock lock;
33 /* List of free pages. */
34 static struct list free_pages;
36 /* Range of pages (expressed as byte pointers to the beginnings
37 of pages) that we haven't added to the free list yet. */
38 static uint8_t *uninit_start, *uninit_end;
40 /* Initializes the page allocator. */
44 extern char _start, _end;
46 /* Kernel static code and data, in 4 kB pages.
47 We can figure this out because the linker records the start
48 and end of the kernel as _start and _end. See
50 size_t kernel_pages = (&_end - &_start + 4095) / 4096;
52 /* Then we know how much is available to allocate. */
53 uninit_start = ptov (LOADER_KERN_BASE + kernel_pages * PGSIZE);
54 uninit_end = ptov (ram_pages * PGSIZE);
56 /* Initialize other variables. */
57 lock_init (&lock, "palloc");
58 list_init (&free_pages);
62 palloc_get (enum palloc_flags flags)
68 if (!list_empty (&free_pages))
69 page = list_entry (list_pop_front (&free_pages), struct page, free_elem);
70 else if (uninit_start < uninit_end)
72 page = (struct page *) uninit_start;
73 uninit_start += PGSIZE;
81 memset (page, 0, PGSIZE);
85 if (flags & PAL_ASSERT)
86 PANIC ("palloc_get: out of pages");
95 palloc_free (void *page_)
97 struct page *page = page_;
99 ASSERT (page == pg_round_down (page));
101 memset (page, 0xcc, PGSIZE);
104 lock_acquire (&lock);
105 list_push_front (&free_pages, &page->free_elem);
106 lock_release (&lock);