kern

annotate src/vm.c @ 45:b8f02479e3f4

mainly additions to the VM to support processes etc. not complete
author John Tsiombikas <nuclear@member.fsf.org>
date Tue, 26 Jul 2011 02:41:33 +0300
parents 5f6c5751ae05
children f65b348780e3
rev   line source
nuclear@17 1 #include <stdio.h>
nuclear@17 2 #include <string.h>
nuclear@17 3 #include <inttypes.h>
nuclear@17 4 #include "vm.h"
nuclear@17 5 #include <stdio.h>
nuclear@17 6 #include "intr.h"
nuclear@17 7 #include "mem.h"
nuclear@17 8 #include "panic.h"
nuclear@17 9
nuclear@17 10
nuclear@17 11 #define KMEM_START 0xc0000000
nuclear@17 12 #define IDMAP_START 0xa0000
nuclear@17 13
nuclear@24 14 #define PGDIR_ADDR 0xfffff000
nuclear@24 15 #define PGTBL_BASE (0xffffffff - 4096 * 1024 + 1)
nuclear@24 16 #define PGTBL(x) ((uint32_t*)(PGTBL_BASE + PGSIZE * (x)))
nuclear@24 17
nuclear@17 18 #define ATTR_PGDIR_MASK 0x3f
nuclear@17 19 #define ATTR_PGTBL_MASK 0x1ff
nuclear@17 20 #define ADDR_PGENT_MASK 0xfffff000
nuclear@17 21
nuclear@17 22 #define PAGEFAULT 14
nuclear@17 23
nuclear@22 24
nuclear@22 25 struct page_range {
nuclear@22 26 int start, end;
nuclear@22 27 struct page_range *next;
nuclear@22 28 };
nuclear@22 29
nuclear@22 30 /* defined in vm-asm.S */
nuclear@22 31 void enable_paging(void);
nuclear@23 32 void disable_paging(void);
nuclear@23 33 int get_paging_status(void);
nuclear@22 34 void set_pgdir_addr(uint32_t addr);
nuclear@23 35 void flush_tlb(void);
nuclear@23 36 void flush_tlb_addr(uint32_t addr);
nuclear@23 37 #define flush_tlb_page(p) flush_tlb_addr(PAGE_TO_ADDR(p))
nuclear@22 38 uint32_t get_fault_addr(void);
nuclear@22 39
nuclear@23 40 static void coalesce(struct page_range *low, struct page_range *mid, struct page_range *high);
nuclear@22 41 static void pgfault(int inum, uint32_t err);
nuclear@22 42 static struct page_range *alloc_node(void);
nuclear@22 43 static void free_node(struct page_range *node);
nuclear@22 44
nuclear@22 45 /* page directory */
nuclear@22 46 static uint32_t *pgdir;
nuclear@22 47
nuclear@22 48 /* 2 lists of free ranges, for kernel memory and user memory */
nuclear@22 49 static struct page_range *pglist[2];
nuclear@22 50 /* list of free page_range structures to be used in the lists */
nuclear@22 51 static struct page_range *node_pool;
nuclear@23 52 /* the first page range for the whole kernel address space, to get things started */
nuclear@23 53 static struct page_range first_node;
nuclear@22 54
nuclear@22 55
nuclear@26 56 void init_vm(void)
nuclear@17 57 {
nuclear@19 58 uint32_t idmap_end;
nuclear@19 59
nuclear@23 60 /* setup the page tables */
nuclear@18 61 pgdir = (uint32_t*)alloc_phys_page();
nuclear@23 62 memset(pgdir, 0, PGSIZE);
nuclear@24 63 set_pgdir_addr((uint32_t)pgdir);
nuclear@17 64
nuclear@17 65 /* map the video memory and kernel code 1-1 */
nuclear@19 66 get_kernel_mem_range(0, &idmap_end);
nuclear@19 67 map_mem_range(IDMAP_START, idmap_end - IDMAP_START, IDMAP_START, 0);
nuclear@17 68
nuclear@24 69 /* make the last page directory entry point to the page directory */
nuclear@24 70 pgdir[1023] = ((uint32_t)pgdir & ADDR_PGENT_MASK) | PG_PRESENT;
nuclear@24 71 pgdir = (uint32_t*)PGDIR_ADDR;
nuclear@24 72
nuclear@23 73 /* set the page fault handler */
nuclear@17 74 interrupt(PAGEFAULT, pgfault);
nuclear@17 75
nuclear@23 76 /* we can enable paging now */
nuclear@17 77 enable_paging();
nuclear@23 78
nuclear@23 79 /* initialize the virtual page allocator */
nuclear@23 80 node_pool = 0;
nuclear@23 81
nuclear@23 82 first_node.start = ADDR_TO_PAGE(KMEM_START);
nuclear@26 83 first_node.end = ADDR_TO_PAGE(PGTBL_BASE);
nuclear@23 84 first_node.next = 0;
nuclear@23 85 pglist[MEM_KERNEL] = &first_node;
nuclear@23 86
nuclear@23 87 pglist[MEM_USER] = alloc_node();
nuclear@26 88 pglist[MEM_USER]->start = ADDR_TO_PAGE(idmap_end);
nuclear@23 89 pglist[MEM_USER]->end = ADDR_TO_PAGE(KMEM_START);
nuclear@23 90 pglist[MEM_USER]->next = 0;
nuclear@17 91 }
nuclear@17 92
nuclear@23 93 /* if ppage == -1 we allocate a physical page by calling alloc_phys_page */
nuclear@23 94 int map_page(int vpage, int ppage, unsigned int attr)
nuclear@17 95 {
nuclear@17 96 uint32_t *pgtbl;
nuclear@25 97 int diridx, pgidx, pgon, intr_state;
nuclear@25 98
nuclear@25 99 intr_state = get_intr_state();
nuclear@25 100 disable_intr();
nuclear@23 101
nuclear@23 102 pgon = get_paging_status();
nuclear@23 103
nuclear@23 104 if(ppage < 0) {
nuclear@23 105 uint32_t addr = alloc_phys_page();
nuclear@23 106 if(!addr) {
nuclear@25 107 set_intr_state(intr_state);
nuclear@23 108 return -1;
nuclear@23 109 }
nuclear@23 110 ppage = ADDR_TO_PAGE(addr);
nuclear@23 111 }
nuclear@23 112
nuclear@23 113 diridx = PAGE_TO_PGTBL(vpage);
nuclear@23 114 pgidx = PAGE_TO_PGTBL_PG(vpage);
nuclear@17 115
nuclear@17 116 if(!(pgdir[diridx] & PG_PRESENT)) {
nuclear@17 117 uint32_t addr = alloc_phys_page();
nuclear@24 118 pgdir[diridx] = addr | (attr & ATTR_PGDIR_MASK) | PG_PRESENT;
nuclear@24 119
nuclear@24 120 pgtbl = pgon ? PGTBL(diridx) : (uint32_t*)addr;
nuclear@18 121 memset(pgtbl, 0, PGSIZE);
nuclear@17 122 } else {
nuclear@24 123 if(pgon) {
nuclear@24 124 pgtbl = PGTBL(diridx);
nuclear@24 125 } else {
nuclear@24 126 pgtbl = (uint32_t*)(pgdir[diridx] & ADDR_PGENT_MASK);
nuclear@24 127 }
nuclear@17 128 }
nuclear@17 129
nuclear@17 130 pgtbl[pgidx] = PAGE_TO_ADDR(ppage) | (attr & ATTR_PGTBL_MASK) | PG_PRESENT;
nuclear@23 131 flush_tlb_page(vpage);
nuclear@23 132
nuclear@25 133 set_intr_state(intr_state);
nuclear@23 134 return 0;
nuclear@17 135 }
nuclear@17 136
nuclear@43 137 int unmap_page(int vpage)
nuclear@17 138 {
nuclear@17 139 uint32_t *pgtbl;
nuclear@43 140 int res = 0;
nuclear@17 141 int diridx = PAGE_TO_PGTBL(vpage);
nuclear@17 142 int pgidx = PAGE_TO_PGTBL_PG(vpage);
nuclear@17 143
nuclear@25 144 int intr_state = get_intr_state();
nuclear@25 145 disable_intr();
nuclear@25 146
nuclear@17 147 if(!(pgdir[diridx] & PG_PRESENT)) {
nuclear@17 148 goto err;
nuclear@17 149 }
nuclear@26 150 pgtbl = PGTBL(diridx);
nuclear@17 151
nuclear@17 152 if(!(pgtbl[pgidx] & PG_PRESENT)) {
nuclear@17 153 goto err;
nuclear@17 154 }
nuclear@17 155 pgtbl[pgidx] = 0;
nuclear@23 156 flush_tlb_page(vpage);
nuclear@17 157
nuclear@25 158 if(0) {
nuclear@17 159 err:
nuclear@25 160 printf("unmap_page(%d): page already not mapped\n", vpage);
nuclear@43 161 res = -1;
nuclear@25 162 }
nuclear@25 163 set_intr_state(intr_state);
nuclear@43 164 return res;
nuclear@17 165 }
nuclear@17 166
nuclear@22 167 /* if ppg_start is -1, we allocate physical pages to map with alloc_phys_page() */
nuclear@23 168 int map_page_range(int vpg_start, int pgcount, int ppg_start, unsigned int attr)
nuclear@17 169 {
nuclear@23 170 int i, phys_pg;
nuclear@17 171
nuclear@17 172 for(i=0; i<pgcount; i++) {
nuclear@26 173 phys_pg = ppg_start < 0 ? -1 : ppg_start + i;
nuclear@23 174 map_page(vpg_start + i, phys_pg, attr);
nuclear@17 175 }
nuclear@23 176 return 0;
nuclear@17 177 }
nuclear@17 178
nuclear@43 179 int unmap_page_range(int vpg_start, int pgcount)
nuclear@43 180 {
nuclear@43 181 int i, res = 0;
nuclear@43 182
nuclear@43 183 for(i=0; i<pgcount; i++) {
nuclear@43 184 if(unmap_page(vpg_start + i) == -1) {
nuclear@43 185 res = -1;
nuclear@43 186 }
nuclear@43 187 }
nuclear@43 188 return res;
nuclear@43 189 }
nuclear@43 190
nuclear@23 191 /* if paddr is 0, we allocate physical pages with alloc_phys_page() */
nuclear@23 192 int map_mem_range(uint32_t vaddr, size_t sz, uint32_t paddr, unsigned int attr)
nuclear@17 193 {
nuclear@17 194 int vpg_start, ppg_start, num_pages;
nuclear@17 195
nuclear@23 196 if(!sz) return -1;
nuclear@17 197
nuclear@17 198 if(ADDR_TO_PGOFFS(paddr)) {
nuclear@17 199 panic("map_mem_range called with unaligned physical address: %x\n", paddr);
nuclear@17 200 }
nuclear@17 201
nuclear@17 202 vpg_start = ADDR_TO_PAGE(vaddr);
nuclear@23 203 ppg_start = paddr > 0 ? ADDR_TO_PAGE(paddr) : -1;
nuclear@17 204 num_pages = ADDR_TO_PAGE(sz) + 1;
nuclear@17 205
nuclear@23 206 return map_page_range(vpg_start, num_pages, ppg_start, attr);
nuclear@17 207 }
nuclear@17 208
nuclear@18 209 uint32_t virt_to_phys(uint32_t vaddr)
nuclear@18 210 {
nuclear@43 211 int pg;
nuclear@43 212 uint32_t pgaddr;
nuclear@43 213
nuclear@43 214 if((pg = virt_to_phys_page(ADDR_TO_PAGE(vaddr))) == -1) {
nuclear@43 215 return 0;
nuclear@43 216 }
nuclear@43 217 pgaddr = PAGE_TO_ADDR(pg);
nuclear@43 218
nuclear@43 219 return pgaddr | ADDR_TO_PGOFFS(vaddr);
nuclear@43 220 }
nuclear@43 221
nuclear@43 222 int virt_to_phys_page(int vpg)
nuclear@43 223 {
nuclear@18 224 uint32_t pgaddr, *pgtbl;
nuclear@43 225 int diridx, pgidx;
nuclear@43 226
nuclear@43 227 if(vpg < 0 || vpg >= PAGE_COUNT) {
nuclear@43 228 return -1;
nuclear@43 229 }
nuclear@43 230
nuclear@43 231 diridx = PAGE_TO_PGTBL(vpg);
nuclear@43 232 pgidx = PAGE_TO_PGTBL_PG(vpg);
nuclear@18 233
nuclear@18 234 if(!(pgdir[diridx] & PG_PRESENT)) {
nuclear@43 235 return -1;
nuclear@18 236 }
nuclear@26 237 pgtbl = PGTBL(diridx);
nuclear@18 238
nuclear@18 239 if(!(pgtbl[pgidx] & PG_PRESENT)) {
nuclear@43 240 return -1;
nuclear@18 241 }
nuclear@18 242 pgaddr = pgtbl[pgidx] & PGENT_ADDR_MASK;
nuclear@43 243 return ADDR_TO_PAGE(pgaddr);
nuclear@18 244 }
nuclear@18 245
nuclear@22 246 /* allocate a contiguous block of virtual memory pages along with
nuclear@22 247 * backing physical memory for them, and update the page table.
nuclear@22 248 */
nuclear@22 249 int pgalloc(int num, int area)
nuclear@22 250 {
nuclear@25 251 int intr_state, ret = -1;
nuclear@22 252 struct page_range *node, *prev, dummy;
nuclear@45 253 unsigned int attr = 0; /* TODO */
nuclear@22 254
nuclear@25 255 intr_state = get_intr_state();
nuclear@25 256 disable_intr();
nuclear@25 257
nuclear@22 258 dummy.next = pglist[area];
nuclear@22 259 node = pglist[area];
nuclear@22 260 prev = &dummy;
nuclear@22 261
nuclear@22 262 while(node) {
nuclear@22 263 if(node->end - node->start >= num) {
nuclear@22 264 ret = node->start;
nuclear@22 265 node->start += num;
nuclear@22 266
nuclear@22 267 if(node->start == node->end) {
nuclear@22 268 prev->next = node->next;
nuclear@22 269 node->next = 0;
nuclear@22 270
nuclear@22 271 if(node == pglist[area]) {
nuclear@22 272 pglist[area] = 0;
nuclear@22 273 }
nuclear@22 274 free_node(node);
nuclear@22 275 }
nuclear@22 276 break;
nuclear@22 277 }
nuclear@22 278
nuclear@22 279 prev = node;
nuclear@22 280 node = node->next;
nuclear@22 281 }
nuclear@22 282
nuclear@22 283 if(ret >= 0) {
nuclear@23 284 /* allocate physical storage and map */
nuclear@45 285 if(map_page_range(ret, num, -1, attr) == -1) {
nuclear@45 286 ret = -1;
nuclear@45 287 }
nuclear@45 288 }
nuclear@45 289
nuclear@45 290 set_intr_state(intr_state);
nuclear@45 291 return ret;
nuclear@45 292 }
nuclear@45 293
nuclear@45 294 int pgalloc_vrange(int start, int num)
nuclear@45 295 {
nuclear@45 296 struct page_range *node, *prev, dummy;
nuclear@45 297 int area, intr_state, ret = -1;
nuclear@45 298 unsigned int attr = 0; /* TODO */
nuclear@45 299
nuclear@45 300 area = (start >= ADDR_TO_PAGE(KMEM_START)) ? MEM_KERNEL : MEM_USER;
nuclear@45 301 if(area == KMEM_USER && start + num > ADDR_TO_PAGE(KMEM_START)) {
nuclear@45 302 printf("pgalloc_vrange: invalid range request crossing user/kernel split\n");
nuclear@45 303 return -1;
nuclear@45 304 }
nuclear@45 305
nuclear@45 306 intr_state = get_intr_state();
nuclear@45 307 disable_intr();
nuclear@45 308
nuclear@45 309 dummy.next = pglist[area];
nuclear@45 310 node = pglist[area];
nuclear@45 311 prev = &dummy;
nuclear@45 312
nuclear@45 313 /* check to see if the requested VM range is available */
nuclear@45 314 node = pglist[area];
nuclear@45 315 while(node) {
nuclear@45 316 if(start >= node->start && start + num <= node->end) {
nuclear@45 317 ret = node->start;
nuclear@45 318 node->start += num;
nuclear@45 319
nuclear@45 320 if(node->start == node->end) {
nuclear@45 321 prev->next = node->next;
nuclear@45 322 node->next = 0;
nuclear@45 323
nuclear@45 324 if(node == pglist[area]) {
nuclear@45 325 pglist[area] = 0;
nuclear@45 326 }
nuclear@45 327 free_node(node);
nuclear@45 328 }
nuclear@45 329 break;
nuclear@45 330 }
nuclear@45 331
nuclear@45 332 prev = node;
nuclear@45 333 node = node->next;
nuclear@45 334 }
nuclear@45 335
nuclear@45 336 if(ret >= 0) {
nuclear@45 337 /* allocate physical storage and map */
nuclear@45 338 if(map_page_range(ret, num, -1, attr) == -1) {
nuclear@23 339 ret = -1;
nuclear@23 340 }
nuclear@22 341 }
nuclear@22 342
nuclear@25 343 set_intr_state(intr_state);
nuclear@22 344 return ret;
nuclear@22 345 }
nuclear@22 346
nuclear@22 347 void pgfree(int start, int num)
nuclear@22 348 {
nuclear@33 349 int i, area, intr_state;
nuclear@23 350 struct page_range *node, *new, *prev, *next;
nuclear@23 351
nuclear@25 352 intr_state = get_intr_state();
nuclear@25 353 disable_intr();
nuclear@25 354
nuclear@26 355 for(i=0; i<num; i++) {
nuclear@43 356 int phys_pg = virt_to_phys_page(start + i);
nuclear@43 357 if(phys_pg != -1) {
nuclear@43 358 free_phys_page(phys_pg);
nuclear@26 359 }
nuclear@26 360 }
nuclear@26 361
nuclear@23 362 if(!(new = alloc_node())) {
nuclear@23 363 panic("pgfree: can't allocate new page_range node to add the freed pages\n");
nuclear@23 364 }
nuclear@23 365 new->start = start;
nuclear@33 366 new->end = start + num;
nuclear@23 367
nuclear@23 368 area = PAGE_TO_ADDR(start) >= KMEM_START ? MEM_KERNEL : MEM_USER;
nuclear@23 369
nuclear@23 370 if(!pglist[area] || pglist[area]->start > start) {
nuclear@23 371 next = new->next = pglist[area];
nuclear@23 372 pglist[area] = new;
nuclear@23 373 prev = 0;
nuclear@23 374
nuclear@23 375 } else {
nuclear@23 376
nuclear@23 377 prev = 0;
nuclear@23 378 node = pglist[area];
nuclear@23 379 next = node ? node->next : 0;
nuclear@23 380
nuclear@23 381 while(node) {
nuclear@23 382 if(!next || next->start > start) {
nuclear@23 383 /* place here, after node */
nuclear@23 384 new->next = next;
nuclear@23 385 node->next = new;
nuclear@23 386 prev = node; /* needed by coalesce after the loop */
nuclear@23 387 break;
nuclear@23 388 }
nuclear@23 389
nuclear@23 390 prev = node;
nuclear@23 391 node = next;
nuclear@23 392 next = node ? node->next : 0;
nuclear@23 393 }
nuclear@23 394 }
nuclear@23 395
nuclear@23 396 coalesce(prev, new, next);
nuclear@25 397 set_intr_state(intr_state);
nuclear@23 398 }
nuclear@23 399
nuclear@23 400 static void coalesce(struct page_range *low, struct page_range *mid, struct page_range *high)
nuclear@23 401 {
nuclear@23 402 if(high) {
nuclear@23 403 if(mid->end == high->start) {
nuclear@23 404 mid->end = high->end;
nuclear@23 405 mid->next = high->next;
nuclear@23 406 free_node(high);
nuclear@23 407 }
nuclear@23 408 }
nuclear@23 409
nuclear@23 410 if(low) {
nuclear@23 411 if(low->end == mid->start) {
nuclear@23 412 low->end += mid->end;
nuclear@23 413 low->next = mid->next;
nuclear@23 414 free_node(mid);
nuclear@23 415 }
nuclear@23 416 }
nuclear@22 417 }
nuclear@22 418
nuclear@17 419 static void pgfault(int inum, uint32_t err)
nuclear@17 420 {
nuclear@17 421 printf("~~~~ PAGE FAULT ~~~~\n");
nuclear@17 422
nuclear@17 423 printf("fault address: %x\n", get_fault_addr());
nuclear@17 424
nuclear@17 425 if(err & PG_PRESENT) {
nuclear@17 426 if(err & 8) {
nuclear@17 427 printf("reserved bit set in some paging structure\n");
nuclear@17 428 } else {
nuclear@17 429 printf("%s protection violation ", (err & PG_WRITABLE) ? "write" : "read");
nuclear@17 430 printf("in %s mode\n", err & PG_USER ? "user" : "kernel");
nuclear@17 431 }
nuclear@17 432 } else {
nuclear@17 433 printf("page not present\n");
nuclear@17 434 }
nuclear@19 435
nuclear@19 436 panic("unhandled page fault\n");
nuclear@17 437 }
nuclear@22 438
nuclear@22 439 /* --- page range list node management --- */
nuclear@23 440 #define NODES_IN_PAGE (PGSIZE / sizeof(struct page_range))
nuclear@23 441
nuclear@22 442 static struct page_range *alloc_node(void)
nuclear@22 443 {
nuclear@22 444 struct page_range *node;
nuclear@23 445 int pg, i;
nuclear@22 446
nuclear@22 447 if(node_pool) {
nuclear@22 448 node = node_pool;
nuclear@22 449 node_pool = node_pool->next;
nuclear@23 450 printf("alloc_node -> %x\n", (unsigned int)node);
nuclear@22 451 return node;
nuclear@22 452 }
nuclear@22 453
nuclear@23 454 /* no node structures in the pool, we need to allocate a new page,
nuclear@23 455 * split it up into node structures, add them in the pool, and
nuclear@23 456 * allocate one of them.
nuclear@22 457 */
nuclear@23 458 if(!(pg = pgalloc(1, MEM_KERNEL))) {
nuclear@22 459 panic("ran out of physical memory while allocating VM range structures\n");
nuclear@22 460 }
nuclear@23 461 node_pool = (struct page_range*)PAGE_TO_ADDR(pg);
nuclear@22 462
nuclear@23 463 /* link them up, skip the first as we'll just allocate it anyway */
nuclear@23 464 for(i=2; i<NODES_IN_PAGE; i++) {
nuclear@23 465 node_pool[i - 1].next = node_pool + i;
nuclear@23 466 }
nuclear@23 467 node_pool[NODES_IN_PAGE - 1].next = 0;
nuclear@23 468
nuclear@23 469 /* grab the first and return it */
nuclear@23 470 node = node_pool++;
nuclear@23 471 printf("alloc_node -> %x\n", (unsigned int)node);
nuclear@23 472 return node;
nuclear@22 473 }
nuclear@22 474
nuclear@22 475 static void free_node(struct page_range *node)
nuclear@22 476 {
nuclear@22 477 node->next = node_pool;
nuclear@22 478 node_pool = node;
nuclear@23 479 printf("free_node\n");
nuclear@22 480 }
nuclear@23 481
nuclear@23 482
nuclear@43 483 /* clone_vmem makes a copy of the current page tables, thus duplicating
nuclear@43 484 * the virtual address space.
nuclear@43 485 *
nuclear@43 486 * Returns the physical address of the new page directory.
nuclear@43 487 */
nuclear@43 488 uint32_t clone_vmem(void)
nuclear@43 489 {
nuclear@43 490 int i, dirpg, tblpg;
nuclear@43 491 uint32_t paddr;
nuclear@43 492 uint32_t *ndir, *ntbl;
nuclear@43 493
nuclear@43 494 if((dirpg = pgalloc(1, MEM_KERNEL)) == -1) {
nuclear@43 495 panic("clone_vmem: failed to allocate page directory page\n");
nuclear@43 496 }
nuclear@43 497 ndir = (uint32_t*)PAGE_TO_ADDR(dirpg);
nuclear@43 498
nuclear@43 499 if((tblpg = pgalloc(1, MEM_KERNEL)) == -1) {
nuclear@43 500 panic("clone_vmem: failed to allocate page table page\n");
nuclear@43 501 }
nuclear@43 502 ntbl = (uint32_t*)PAGE_TO_ADDR(tblpg);
nuclear@43 503
nuclear@43 504 /* we will allocate physical pages and map them to this virtual page
nuclear@43 505 * as needed in the loop below.
nuclear@43 506 */
nuclear@43 507 free_phys_page(virt_to_phys(tblpg));
nuclear@43 508
nuclear@43 509 for(i=0; i<1024; i++) {
nuclear@43 510 if(pgdir[i] & PG_PRESENT) {
nuclear@43 511 paddr = alloc_phys_page();
nuclear@43 512 map_page(tblpg, ADDR_TO_PAGE(paddr), 0);
nuclear@43 513
nuclear@43 514 /* copy the page table */
nuclear@43 515 memcpy(ntbl, PGTBL(i), PGSIZE);
nuclear@43 516
nuclear@43 517 /* set the new page directory entry */
nuclear@43 518 ndir[i] = paddr | (pgdir[i] & PGOFFS_MASK);
nuclear@43 519 } else {
nuclear@43 520 ndir[i] = 0;
nuclear@43 521 }
nuclear@43 522 }
nuclear@43 523
nuclear@43 524 paddr = virt_to_phys(dirpg);
nuclear@43 525
nuclear@43 526 /* unmap before freeing to avoid deallocating the physical pages */
nuclear@43 527 unmap_page(dirpg);
nuclear@43 528 unmap_page(tblpg);
nuclear@43 529
nuclear@43 530 pgfree(dirpg, 1);
nuclear@43 531 pgfree(tblpg, 1);
nuclear@43 532
nuclear@43 533 return paddr;
nuclear@43 534 }
nuclear@43 535
nuclear@43 536
nuclear@23 537 void dbg_print_vm(int area)
nuclear@23 538 {
nuclear@25 539 struct page_range *node;
nuclear@25 540 int last, intr_state;
nuclear@25 541
nuclear@25 542 intr_state = get_intr_state();
nuclear@25 543 disable_intr();
nuclear@25 544
nuclear@25 545 node = pglist[area];
nuclear@25 546 last = area == MEM_USER ? 0 : ADDR_TO_PAGE(KMEM_START);
nuclear@23 547
nuclear@23 548 printf("%s vm space\n", area == MEM_USER ? "user" : "kernel");
nuclear@23 549
nuclear@23 550 while(node) {
nuclear@23 551 if(node->start > last) {
nuclear@23 552 printf(" vm-used: %x -> %x\n", PAGE_TO_ADDR(last), PAGE_TO_ADDR(node->start));
nuclear@23 553 }
nuclear@23 554
nuclear@23 555 printf(" vm-free: %x -> ", PAGE_TO_ADDR(node->start));
nuclear@23 556 if(node->end >= PAGE_COUNT) {
nuclear@23 557 printf("END\n");
nuclear@23 558 } else {
nuclear@23 559 printf("%x\n", PAGE_TO_ADDR(node->end));
nuclear@23 560 }
nuclear@23 561
nuclear@23 562 last = node->end;
nuclear@23 563 node = node->next;
nuclear@23 564 }
nuclear@25 565
nuclear@25 566 set_intr_state(intr_state);
nuclear@23 567 }