00001 #include "threads/palloc.h"
00002
00003 #include <bitmap.h>
00004 #include <debug.h>
00005 #include <inttypes.h>
00006 #include <round.h>
00007 #include <stddef.h>
00008 #include <stdint.h>
00009 #include <stdio.h>
00010 #include <string.h>
00011 #include "threads/loader.h"
00012 #include "threads/synch.h"
00013 #include "threads/vaddr.h"
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 struct pool
00031 {
00032 struct lock lock;
00033 struct bitmap *used_map;
00034 uint8_t *base;
00035 };
00036
00037
00038 struct pool kernel_pool, user_pool;
00039
00040
00041 size_t user_page_limit = SIZE_MAX;
00042
00043 static void init_pool (struct pool *, void *base, size_t page_cnt,
00044 const char *name);
00045 static bool page_from_pool (const struct pool *, void *page);
00046
00047
00048 void
00049 palloc_init (void)
00050 {
00051
00052 uint8_t *free_start = ptov (1024 * 1024);
00053 uint8_t *free_end = ptov (ram_pages * PGSIZE);
00054 size_t free_pages = (free_end - free_start) / PGSIZE;
00055 size_t user_pages = free_pages / 2;
00056 size_t kernel_pages;
00057 if (user_pages > user_page_limit)
00058 user_pages = user_page_limit;
00059 kernel_pages = free_pages - user_pages;
00060
00061
00062 init_pool (&kernel_pool, free_start, kernel_pages, "kernel pool");
00063 init_pool (&user_pool, free_start + kernel_pages * PGSIZE,
00064 user_pages, "user pool");
00065 }
00066
00067
00068
00069
00070
00071
00072
00073 void *
00074 palloc_get_multiple (enum palloc_flags flags, size_t page_cnt)
00075 {
00076 struct pool *pool = flags & PAL_USER ? &user_pool : &kernel_pool;
00077 void *pages;
00078 size_t page_idx;
00079
00080 if (page_cnt == 0)
00081 return NULL;
00082
00083 lock_acquire (&pool->lock);
00084 page_idx = bitmap_scan_and_flip (pool->used_map, 0, page_cnt, false);
00085 lock_release (&pool->lock);
00086
00087 if (page_idx != BITMAP_ERROR)
00088 pages = pool->base + PGSIZE * page_idx;
00089 else
00090 pages = NULL;
00091
00092 if (pages != NULL)
00093 {
00094 if (flags & PAL_ZERO)
00095 memset (pages, 0, PGSIZE * page_cnt);
00096 }
00097 else
00098 {
00099 if (flags & PAL_ASSERT)
00100 PANIC ("palloc_get: out of pages");
00101 }
00102
00103 return pages;
00104 }
00105
00106
00107
00108
00109
00110
00111
00112
00113 void *
00114 palloc_get_page (enum palloc_flags flags)
00115 {
00116 return palloc_get_multiple (flags, 1);
00117 }
00118
00119
00120 void
00121 palloc_free_multiple (void *pages, size_t page_cnt)
00122 {
00123 struct pool *pool;
00124 size_t page_idx;
00125
00126 ASSERT (pg_ofs (pages) == 0);
00127 if (pages == NULL || page_cnt == 0)
00128 return;
00129
00130 if (page_from_pool (&kernel_pool, pages))
00131 pool = &kernel_pool;
00132 else if (page_from_pool (&user_pool, pages))
00133 pool = &user_pool;
00134 else
00135 NOT_REACHED ();
00136
00137 page_idx = pg_no (pages) - pg_no (pool->base);
00138
00139 #ifndef NDEBUG
00140 memset (pages, 0xcc, PGSIZE * page_cnt);
00141 #endif
00142
00143 ASSERT (bitmap_all (pool->used_map, page_idx, page_cnt));
00144 bitmap_set_multiple (pool->used_map, page_idx, page_cnt, false);
00145 }
00146
00147
00148 void
00149 palloc_free_page (void *page)
00150 {
00151 palloc_free_multiple (page, 1);
00152 }
00153
00154
00155
00156 static void
00157 init_pool (struct pool *p, void *base, size_t page_cnt, const char *name)
00158 {
00159
00160
00161
00162 size_t bm_pages = DIV_ROUND_UP (bitmap_buf_size (page_cnt), PGSIZE);
00163 if (bm_pages > page_cnt)
00164 PANIC ("Not enough memory in %s for bitmap.", name);
00165 page_cnt -= bm_pages;
00166
00167 printf ("%zu pages available in %s.\n", page_cnt, name);
00168
00169
00170 lock_init (&p->lock);
00171 p->used_map = bitmap_create_in_buf (page_cnt, base, bm_pages * PGSIZE);
00172 p->base = base + bm_pages * PGSIZE;
00173 }
00174
00175
00176
00177 static bool
00178 page_from_pool (const struct pool *pool, void *page)
00179 {
00180 size_t page_no = pg_no (page);
00181 size_t start_page = pg_no (pool->base);
00182 size_t end_page = start_page + bitmap_size (pool->used_map);
00183
00184 return page_no >= start_page && page_no < end_page;
00185 }