From 21ac7c268fb270b95eb01e04a2d331c709e911f4 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Sun, 30 Jan 2005 22:04:14 +0000 Subject: [PATCH] Rewrite palloc code so that it only touches the first 4 MB of RAM. This lets us simplify the start.S code so it only needs to create a page table for the first 4 MB of RAM. --- src/threads/init.c | 20 +++----- src/threads/palloc.c | 111 +++++++++++++++++++++---------------------- src/threads/palloc.h | 2 +- 3 files changed, 62 insertions(+), 71 deletions(-) diff --git a/src/threads/init.c b/src/threads/init.c index b98e580..3b31328 100644 --- a/src/threads/init.c +++ b/src/threads/init.c @@ -78,8 +78,8 @@ main (void) argv_init (); /* Initialize memory system. */ - paging_init (); palloc_init (); + paging_init (); malloc_init (); /* Segmentation. */ @@ -168,8 +168,8 @@ paging_init (void) uint32_t *pd, *pt; size_t page; - pd = base_page_dir = ptov (LOADER_PD_BASE); - pt = ptov (LOADER_PT_BASE); + pd = base_page_dir = palloc_get_page (PAL_ASSERT | PAL_ZERO); + pt = NULL; for (page = 0; page < ram_pages; page++) { uintptr_t paddr = page * PGSIZE; @@ -179,22 +179,16 @@ paging_init (void) if (pd[pde_idx] == 0) { - pt += PGSIZE / sizeof *pt; - memset (pt, 0, PGSIZE); + pt = palloc_get_page (PAL_ASSERT | PAL_ZERO); pd[pde_idx] = pde_create (pt); } pt[pte_idx] = pte_create_kernel (vaddr, true); } - /* start.S mapped the beginning of physical memory to virtual - address 0. We don't want that mapping anymore, so erase - it. */ - pd[0] = 0; - /* Store the physical address of the page directory into CR3 - aka PDBR (page directory base register). This flushes the - TLB to make sure . See [IA32-v2a] "MOV--Move + aka PDBR (page directory base register). This activates our + new page tables immediately. See [IA32-v2a] "MOV--Move to/from Control Registers" and [IA32-v3] 3.7.5. */ asm volatile ("mov %%cr3, %0" :: "r" (vtop (base_page_dir))); } @@ -237,7 +231,7 @@ argv_init (void) else if (!strcmp (argv[i], "-ex")) initial_program = argv[++i]; else if (!strcmp (argv[i], "-ul")) - user_page_limit = atoi (argv[++i]); + max_user_pages = atoi (argv[++i]); #endif #ifdef FILESYS else if (!strcmp (argv[i], "-f")) diff --git a/src/threads/palloc.c b/src/threads/palloc.c index 545a7d4..544dca9 100644 --- a/src/threads/palloc.c +++ b/src/threads/palloc.c @@ -29,18 +29,21 @@ /* A memory pool. */ struct pool { - struct lock lock; /* Mutual exclusion. */ - struct bitmap *used_map; /* Bitmap of free pages. */ - uint8_t *base; /* Base of pool. */ + size_t first_page; /* Page number of first page. */ + size_t page_cnt; /* Number of pages. */ }; +/* Tracks pages in use, with a lock protecting it. */ +static struct bitmap *used_map; +static struct lock used_map_lock; + /* Two pools: one for kernel data, one for user pages. */ -struct pool kernel_pool, user_pool; +static struct pool kernel_pool, user_pool; /* Maximum number of pages to put in user pool. */ -size_t user_page_limit = SIZE_MAX; +size_t max_user_pages = SIZE_MAX; -static void init_pool (struct pool *, void *base, size_t page_cnt, +static void init_pool (struct pool *pool, size_t first_page, size_t page_cnt, const char *name); static bool page_from_pool (const struct pool *, void *page); @@ -48,24 +51,37 @@ static bool page_from_pool (const struct pool *, void *page); void palloc_init (void) { - /* End of the kernel as recorded by the linker. - See kernel.lds.S. */ - extern char _end; - - /* Free memory. */ - uint8_t *free_start = pg_round_up (&_end); - uint8_t *free_end = ptov (ram_pages * PGSIZE); - size_t free_pages = (free_end - free_start) / PGSIZE; - size_t user_pages = free_pages / 2; - size_t kernel_pages; - if (user_pages > user_page_limit) - user_pages = user_page_limit; - kernel_pages = free_pages - user_pages; - - /* Give half of memory to kernel, half to user. */ + /* used_map from 1 MB as long as necessary. */ + size_t bitmap_start = 1024; + size_t bitmap_pages = DIV_ROUND_UP (bitmap_needed_bytes (ram_pages), PGSIZE); + + /* Free space from the bitmap to the end of RAM. */ + size_t free_start = bitmap_start + bitmap_pages; + size_t free_pages = ram_pages - free_start; + + /* Kernel and user get half of free space each. + User space can be limited by max_user_pages. */ + size_t half_free = free_pages / 2; + size_t kernel_pages = half_free; + size_t user_pages = half_free < max_user_pages ? half_free : max_user_pages; + + used_map = bitmap_create_preallocated (ram_pages, + ptov (bitmap_start * PGSIZE), + bitmap_pages * PGSIZE); init_pool (&kernel_pool, free_start, kernel_pages, "kernel pool"); - init_pool (&user_pool, free_start + kernel_pages * PGSIZE, - user_pages, "user pool"); + init_pool (&user_pool, free_start + kernel_pages, user_pages, "use pool"); + lock_init (&used_map_lock, "used_map"); +} + +/* Initializes POOL to start (named NAME) at physical page number + FIRST_PAGE and continue for PAGE_CNT pages. */ +static void +init_pool (struct pool *pool, size_t first_page, size_t page_cnt, + const char *name) +{ + printf ("%zu pages available in %s.\n", page_cnt, name); + pool->first_page = first_page; + pool->page_cnt = page_cnt; } /* Obtains and returns a group of PAGE_CNT contiguous free pages. @@ -77,19 +93,23 @@ palloc_init (void) void * palloc_get_multiple (enum palloc_flags flags, size_t page_cnt) { - struct pool *pool = flags & PAL_USER ? &user_pool : &kernel_pool; + struct pool *pool; void *pages; size_t page_idx; if (page_cnt == 0) return NULL; - lock_acquire (&pool->lock); - page_idx = bitmap_scan_and_flip (pool->used_map, 0, page_cnt, false); - lock_release (&pool->lock); + pool = flags & PAL_USER ? &user_pool : &kernel_pool; + + lock_acquire (&used_map_lock); + page_idx = bitmap_scan_and_flip (used_map, + pool->first_page, pool->page_cnt, + false); + lock_release (&used_map_lock); if (page_idx != BITMAP_ERROR) - pages = pool->base + PGSIZE * page_idx; + pages = ptov (PGSIZE * page_idx); else pages = NULL; @@ -137,14 +157,14 @@ palloc_free_multiple (void *pages, size_t page_cnt) else NOT_REACHED (); - page_idx = pg_no (pages) - pg_no (pool->base); + page_idx = vtop (pages) / PGSIZE; #ifndef NDEBUG memset (pages, 0xcc, PGSIZE * page_cnt); #endif - ASSERT (bitmap_all (pool->used_map, page_idx, page_cnt)); - bitmap_set_multiple (pool->used_map, page_idx, page_cnt, false); + ASSERT (bitmap_all (used_map, page_idx, page_cnt)); + bitmap_set_multiple (used_map, page_idx, page_cnt, false); } /* Frees the page at PAGE. */ @@ -154,36 +174,13 @@ palloc_free_page (void *page) palloc_free_multiple (page, 1); } -/* Initializes pool P as starting at START and ending at END, - naming it NAME for debugging purposes. */ -static void -init_pool (struct pool *p, void *base, size_t page_cnt, const char *name) -{ - /* We'll put the pool's used_map at its base. - Calculate the space needed for the bitmap - and subtract it from the pool's size. */ - size_t bm_pages = DIV_ROUND_UP (bitmap_needed_bytes (page_cnt), PGSIZE); - if (bm_pages > page_cnt) - PANIC ("Not enough memory in %s for bitmap.", name); - page_cnt -= bm_pages; - - printf ("%zu pages available in %s.\n", page_cnt, name); - - /* Initialize the pool. */ - lock_init (&p->lock, name); - p->used_map = bitmap_create_preallocated (page_cnt, base, - bm_pages * PGSIZE); - p->base = base + bm_pages * PGSIZE; -} - /* Returns true if PAGE was allocated from POOL, false otherwise. */ static bool page_from_pool (const struct pool *pool, void *page) { - size_t page_no = pg_no (page); - size_t start_page = pg_no (pool->base); - size_t end_page = start_page + bitmap_size (pool->used_map); + size_t phys_page_no = vtop (page) / PGSIZE; - return page_no >= start_page && page_no < end_page; + return (phys_page_no >= pool->first_page + && phys_page_no < pool->first_page + pool->page_cnt); } diff --git a/src/threads/palloc.h b/src/threads/palloc.h index 2d41cf6..44cfb0e 100644 --- a/src/threads/palloc.h +++ b/src/threads/palloc.h @@ -12,7 +12,7 @@ enum palloc_flags }; /* Maximum number of pages to put in user pool. */ -extern size_t user_page_limit; +extern size_t max_user_pages; void palloc_init (void); void *palloc_get_page (enum palloc_flags); -- 2.30.2