1 /* 2 * Copyright 2007, Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * François Revol <revol@free.fr> 7 * 8 * Copyright 2003-2007, Axel Dörfler, axeld@pinc-software.de. 9 * Distributed under the terms of the MIT License. 10 * 11 * Copyright 2001, Travis Geiselbrecht. All rights reserved. 12 * Distributed under the terms of the NewOS License. 13 */ 14 15 #ifndef ARCH_M68K_MMU_TYPE 16 #error This file is included from arch_*_mmu.cpp 17 #endif 18 19 /* (mmu_man) Implementation details on 68030 and others: 20 21 Unlike on x86 we can't just switch the context to another team by just 22 setting a register to another page directory, since we only have one 23 page table containing both kernel and user address mappings. 24 The 030 supports arbitrary layout of the page directory tree, including 25 a 1-bit first level (2 entries top level table) that would map kernel 26 and user land at a single place. But 040 and later only support a fixed 27 splitting of 7/7/6 for 4K pages. 28 29 Since 68k SMP hardware is rare enough we don't want to support them, we 30 can take some shortcuts. 31 32 As we don't want a separate user and kernel space, we'll use a single 33 table. With the 7/7/6 split the 2nd level would require 32KB of tables, 34 which is small enough to not want to use the list hack from x86. 35 XXX: we use the hack for now, check later 36 37 Since page directories/tables don't fit exactly a page, we stuff more 38 than one per page, and allocate them all at once, and add them at the 39 same time to the tree. So we guarantee all higher-level entries modulo 40 the number of tables/page are either invalid or present. 41 */ 42 43 #include <KernelExport.h> 44 #include <kernel.h> 45 #include <vm.h> 46 #include <vm_address_space.h> 47 #include <vm_priv.h> 48 #include <int.h> 49 #include <boot/kernel_args.h> 50 #include <arch/vm_translation_map.h> 51 #include <arch/cpu.h> 52 #include <arch_mmu.h> 53 #include <stdlib.h> 54 55 #include "generic_vm_physical_page_mapper.h" 56 57 58 59 //#define TRACE_VM_TMAP 60 #ifdef TRACE_VM_TMAP 61 # define TRACE(x) dprintf x 62 #else 63 # define TRACE(x) ; 64 #endif 65 66 //XXX: that's platform specific! 67 // 14 MB of iospace 68 #define IOSPACE_SIZE (14*1024*1024) 69 // 4 MB chunks, to optimize for 4 MB pages 70 // XXX: no such thing on 68k (060 ?) 71 // 256K 72 #define IOSPACE_CHUNK_SIZE (256*1024) 73 74 static page_table_entry *iospace_pgtables = NULL; 75 76 #define PAGE_INVALIDATE_CACHE_SIZE 64 77 78 // vm_translation object stuff 79 typedef struct vm_translation_map_arch_info { 80 page_root_entry *rtdir_virt; 81 page_root_entry *rtdir_phys; 82 int num_invalidate_pages; 83 addr_t pages_to_invalidate[PAGE_INVALIDATE_CACHE_SIZE]; 84 } vm_translation_map_arch_info; 85 86 #if 1//XXX ? 87 static page_table_entry *page_hole = NULL; 88 static page_directory_entry *page_hole_pgdir = NULL; 89 #endif 90 static page_root_entry *sKernelPhysicalPageRoot = NULL; 91 static page_root_entry *sKernelVirtualPageRoot = NULL; 92 static addr_t sQueryPage = NULL; 93 //static page_table_entry *sQueryPageTable; 94 //static page_directory_entry *sQueryPageDir; 95 // MUST be aligned 96 static page_table_entry sQueryDesc __attribute__ (( aligned (4) )); 97 98 static vm_translation_map *tmap_list; 99 static spinlock tmap_list_lock; 100 101 static addr_t sIOSpaceBase; 102 103 #define CHATTY_TMAP 0 104 105 #if 0 106 // use P*E_TO_* and TA_TO_P*EA ! 107 #define ADDR_SHIFT(x) ((x)>>12) 108 #define ADDR_REVERSE_SHIFT(x) ((x)<<12) 109 #endif 110 111 /* 7/7/6 split */ 112 #define VADDR_TO_PRENT(va) (((va) / B_PAGE_SIZE) / (64*128)) 113 #define VADDR_TO_PDENT(va) ((((va) / B_PAGE_SIZE) / 64) % 128) 114 #define VADDR_TO_PTENT(va) (((va) / B_PAGE_SIZE) % 64) 115 116 #define FIRST_USER_PGROOT_ENT (VADDR_TO_PRENT(USER_BASE)) 117 #define FIRST_USER_PGDIR_ENT (VADDR_TO_PDENT(USER_BASE)) 118 #define NUM_USER_PGROOT_ENTS (VADDR_TO_PRENT(ROUNDUP(USER_SIZE, B_PAGE_SIZE * 64 * 128))) 119 #define NUM_USER_PGDIR_ENTS (VADDR_TO_PDENT(ROUNDUP(USER_SIZE, B_PAGE_SIZE * 64))) 120 #define FIRST_KERNEL_PGROOT_ENT (VADDR_TO_PRENT(KERNEL_BASE)) 121 #define FIRST_KERNEL_PGDIR_ENT (VADDR_TO_PDENT(KERNEL_BASE)) 122 #define NUM_KERNEL_PGROOT_ENTS (VADDR_TO_PRENT(KERNEL_SIZE)) 123 #define NUM_KERNEL_PGDIR_ENTS (VADDR_TO_PDENT(KERNEL_SIZE)) 124 #define IS_KERNEL_MAP(map) (map->arch_data->rtdir_phys == sKernelPhysicalPageRoot) 125 126 static status_t early_query(addr_t va, addr_t *out_physical); 127 static status_t get_physical_page_tmap(addr_t pa, addr_t *va, uint32 flags); 128 static status_t put_physical_page_tmap(addr_t va); 129 130 static void flush_tmap(vm_translation_map *map); 131 132 133 static void * 134 m68k_translation_map_get_pgdir(vm_translation_map *map) 135 { 136 return map->arch_data->rtdir_phys; 137 } 138 139 140 static inline void 141 init_page_root_entry(page_root_entry *entry) 142 { 143 // DT_INVALID is 0 144 *(page_root_entry_scalar *)entry = DFL_ROOTENT_VAL; 145 } 146 147 148 static inline void 149 update_page_root_entry(page_root_entry *entry, page_root_entry *with) 150 { 151 // update page directory entry atomically 152 *(page_root_entry_scalar *)entry = *(page_root_entry_scalar *)with; 153 } 154 155 156 static inline void 157 init_page_directory_entry(page_directory_entry *entry) 158 { 159 *(page_directory_entry_scalar *)entry = DFL_DIRENT_VAL; 160 } 161 162 163 static inline void 164 update_page_directory_entry(page_directory_entry *entry, page_directory_entry *with) 165 { 166 // update page directory entry atomically 167 *(page_directory_entry_scalar *)entry = *(page_directory_entry_scalar *)with; 168 } 169 170 171 static inline void 172 init_page_table_entry(page_table_entry *entry) 173 { 174 *(page_table_entry_scalar *)entry = DFL_PAGEENT_VAL; 175 } 176 177 178 static inline void 179 update_page_table_entry(page_table_entry *entry, page_table_entry *with) 180 { 181 // update page table entry atomically 182 // XXX: is it ?? (long desc?) 183 *(page_table_entry_scalar *)entry = *(page_table_entry_scalar *)with; 184 } 185 186 187 static void 188 _update_all_pgdirs(int index, page_root_entry e) 189 { 190 vm_translation_map *entry; 191 unsigned int state = disable_interrupts(); 192 193 acquire_spinlock(&tmap_list_lock); 194 195 for(entry = tmap_list; entry != NULL; entry = entry->next) 196 entry->arch_data->rtdir_virt[index] = e; 197 198 release_spinlock(&tmap_list_lock); 199 restore_interrupts(state); 200 } 201 202 203 // XXX currently assumes this translation map is active 204 205 static status_t 206 early_query(addr_t va, addr_t *_physicalAddress) 207 { 208 page_table_entry *pentry; 209 210 if (page_hole_pgdir[VADDR_TO_PDENT(va)].type != DT_DIR) { 211 // no pagetable here 212 return B_ERROR; 213 } 214 #warning M68K: va or VADDR_TO_PTENT(va) ?? 215 pentry = page_hole + va / B_PAGE_SIZE; 216 if (pentry->type != DT_PAGE) { 217 // page mapping not valid 218 return B_ERROR; 219 } 220 221 *_physicalAddress = PTE_TO_PA(*pentry); 222 return B_OK; 223 } 224 225 226 /*! Acquires the map's recursive lock, and resets the invalidate pages counter 227 in case it's the first locking recursion. 228 */ 229 static status_t 230 lock_tmap(vm_translation_map *map) 231 { 232 TRACE(("lock_tmap: map %p\n", map)); 233 234 recursive_lock_lock(&map->lock); 235 if (recursive_lock_get_recursion(&map->lock) == 1) { 236 // we were the first one to grab the lock 237 TRACE(("clearing invalidated page count\n")); 238 map->arch_data->num_invalidate_pages = 0; 239 } 240 241 return B_OK; 242 } 243 244 245 /*! Unlocks the map, and, if we'll actually losing the recursive lock, 246 flush all pending changes of this map (ie. flush TLB caches as 247 needed). 248 */ 249 static status_t 250 unlock_tmap(vm_translation_map *map) 251 { 252 TRACE(("unlock_tmap: map %p\n", map)); 253 254 if (recursive_lock_get_recursion(&map->lock) == 1) { 255 // we're about to release it for the last time 256 flush_tmap(map); 257 } 258 259 recursive_lock_unlock(&map->lock); 260 return B_OK; 261 } 262 263 264 static void 265 destroy_tmap(vm_translation_map *map) 266 { 267 int state; 268 vm_translation_map *entry; 269 vm_translation_map *last = NULL; 270 unsigned int i, j; 271 272 if (map == NULL) 273 return; 274 275 // remove it from the tmap list 276 state = disable_interrupts(); 277 acquire_spinlock(&tmap_list_lock); 278 279 entry = tmap_list; 280 while (entry != NULL) { 281 if (entry == map) { 282 if (last != NULL) 283 last->next = entry->next; 284 else 285 tmap_list = entry->next; 286 287 break; 288 } 289 last = entry; 290 entry = entry->next; 291 } 292 293 release_spinlock(&tmap_list_lock); 294 restore_interrupts(state); 295 296 if (map->arch_data->rtdir_virt != NULL) { 297 // cycle through and free all of the user space pgtables 298 // since the size of tables don't match B_PAEG_SIZE, 299 // we alloc several at once, based on modulos, 300 // we make sure they are either all in the tree or none. 301 for (i = VADDR_TO_PRENT(USER_BASE); i <= VADDR_TO_PRENT(USER_BASE + (USER_SIZE - 1)); i++) { 302 addr_t pgdir_pn; 303 page_directory_entry *pgdir; 304 vm_page *dirpage; 305 306 if (map->arch_data->rtdir_virt[i].type == DT_INVALID) 307 continue; 308 if (map->arch_data->rtdir_virt[i].type != DT_ROOT) { 309 panic("rtdir[%d]: buggy descriptor type", i); 310 return; 311 } 312 // suboptimal (done 8 times) 313 pgdir_pn = PRE_TO_PA(map->arch_data->rtdir_virt[i]); 314 dirpage = vm_lookup_page(pgdir_pn); 315 pgdir = &(((page_directory_entry *)dirpage)[i%NUM_DIRTBL_PER_PAGE]); 316 317 for (j = 0; j <= NUM_DIRENT_PER_TBL; j+=NUM_PAGETBL_PER_PAGE) { 318 addr_t pgtbl_pn; 319 page_table_entry *pgtbl; 320 vm_page *page; 321 if (pgdir[j].type == DT_INVALID) 322 continue; 323 if (pgdir[j].type != DT_DIR) { 324 panic("rtdir[%d][%d]: buggy descriptor type", i, j); 325 return; 326 } 327 pgtbl_pn = PDE_TO_PN(pgdir[j]); 328 page = vm_lookup_page(pgtbl_pn); 329 pgtbl = (page_table_entry *)page; 330 331 if (!page) { 332 panic("destroy_tmap: didn't find pgtable page\n"); 333 return; 334 } 335 vm_page_set_state(page, PAGE_STATE_FREE); 336 } 337 if (((i+1)%NUM_DIRTBL_PER_PAGE) == 0) 338 vm_page_set_state(dirpage, PAGE_STATE_FREE); 339 } 340 free(map->arch_data->rtdir_virt); 341 } 342 343 free(map->arch_data); 344 recursive_lock_destroy(&map->lock); 345 } 346 347 348 static void 349 put_pgdir_in_pgroot(page_root_entry *entry, 350 addr_t pgdir_phys, uint32 attributes) 351 { 352 page_root_entry dir; 353 // put it in the pgdir 354 init_page_root_entry(&dir); 355 dir.addr = TA_TO_PREA(pgdir_phys); 356 357 // ToDo: we ignore the attributes of the page table - for compatibility 358 // with BeOS we allow having user accessible areas in the kernel address 359 // space. This is currently being used by some drivers, mainly for the 360 // frame buffer. Our current real time data implementation makes use of 361 // this fact, too. 362 // We might want to get rid of this possibility one day, especially if 363 // we intend to port it to a platform that does not support this. 364 //dir.user = 1; 365 //dir.rw = 1; 366 dir.type = DT_ROOT; 367 update_page_root_entry(entry, &dir); 368 } 369 370 371 static void 372 put_pgtable_in_pgdir(page_directory_entry *entry, 373 addr_t pgtable_phys, uint32 attributes) 374 { 375 page_directory_entry table; 376 // put it in the pgdir 377 init_page_directory_entry(&table); 378 table.addr = TA_TO_PDEA(pgtable_phys); 379 380 // ToDo: we ignore the attributes of the page table - for compatibility 381 // with BeOS we allow having user accessible areas in the kernel address 382 // space. This is currently being used by some drivers, mainly for the 383 // frame buffer. Our current real time data implementation makes use of 384 // this fact, too. 385 // We might want to get rid of this possibility one day, especially if 386 // we intend to port it to a platform that does not support this. 387 //table.user = 1; 388 //table.rw = 1; 389 table.type = DT_DIR; 390 update_page_directory_entry(entry, &table); 391 } 392 393 394 static void 395 put_page_table_entry_in_pgtable(page_table_entry *entry, 396 addr_t physicalAddress, uint32 attributes, bool globalPage) 397 { 398 page_table_entry page; 399 init_page_table_entry(&page); 400 401 page.addr = TA_TO_PTEA(physicalAddress); 402 403 // if the page is user accessible, it's automatically 404 // accessible in kernel space, too (but with the same 405 // protection) 406 page.supervisor = (attributes & B_USER_PROTECTION) == 0; 407 if (page.supervisor) 408 page.write_protect = (attributes & B_KERNEL_WRITE_AREA) == 0; 409 else 410 page.write_protect = (attributes & B_WRITE_AREA) == 0; 411 page.type = DT_PAGE; 412 413 #ifdef PAGE_HAS_GLOBAL_BIT 414 if (globalPage) 415 page.global = 1; 416 #endif 417 418 // put it in the page table 419 update_page_table_entry(entry, &page); 420 } 421 422 423 static void 424 put_page_indirect_entry_in_pgtable(page_indirect_entry *entry, 425 addr_t physicalAddress, uint32 attributes, bool globalPage) 426 { 427 page_indirect_entry page; 428 init_page_table_entry(&page); 429 430 page.addr = TA_TO_PIEA(physicalAddress); 431 page.type = DT_INDIRECT; 432 433 // there are no protection bits in indirect descriptor usually. 434 435 // put it in the page table 436 update_page_table_entry(entry, &page); 437 } 438 439 440 static size_t 441 map_max_pages_need(vm_translation_map */*map*/, addr_t start, addr_t end) 442 { 443 size_t need; 444 size_t pgdirs = VADDR_TO_PRENT(end) + 1 - VADDR_TO_PRENT(start); 445 // how much for page directories 446 need = (pgdirs + NUM_DIRTBL_PER_PAGE - 1) / NUM_DIRTBL_PER_PAGE; 447 // and page tables themselves 448 need = ((pgdirs * NUM_DIRENT_PER_TBL) + NUM_PAGETBL_PER_PAGE - 1) / NUM_PAGETBL_PER_PAGE; 449 450 // better rounding when only 1 pgdir 451 // XXX: do better for other cases 452 if (pgdirs == 1) { 453 need = 1; 454 need += (VADDR_TO_PDENT(end) + 1 - VADDR_TO_PDENT(start) + NUM_PAGETBL_PER_PAGE - 1) / NUM_PAGETBL_PER_PAGE; 455 } 456 457 return need; 458 } 459 460 461 static status_t 462 map_tmap(vm_translation_map *map, addr_t va, addr_t pa, uint32 attributes) 463 { 464 page_root_entry *pr; 465 page_directory_entry *pd; 466 page_table_entry *pt; 467 addr_t pd_pg, pt_pg; 468 unsigned int rindex, dindex, pindex; 469 int err; 470 471 TRACE(("map_tmap: entry pa 0x%lx va 0x%lx\n", pa, va)); 472 473 /* 474 dprintf("pgdir at 0x%x\n", pgdir); 475 dprintf("index is %d\n", va / B_PAGE_SIZE / 1024); 476 dprintf("final at 0x%x\n", &pgdir[va / B_PAGE_SIZE / 1024]); 477 dprintf("value is 0x%x\n", *(int *)&pgdir[va / B_PAGE_SIZE / 1024]); 478 dprintf("present bit is %d\n", pgdir[va / B_PAGE_SIZE / 1024].present); 479 dprintf("addr is %d\n", pgdir[va / B_PAGE_SIZE / 1024].addr); 480 */ 481 pr = map->arch_data->rtdir_virt; 482 483 // check to see if a page directory exists for this range 484 rindex = VADDR_TO_PRENT(va); 485 if (pr[rindex].type != DT_ROOT) { 486 addr_t pgdir; 487 vm_page *page; 488 unsigned int i; 489 490 // we need to allocate a pgtable 491 page = vm_page_allocate_page(PAGE_STATE_CLEAR, true); 492 493 // mark the page WIRED 494 vm_page_set_state(page, PAGE_STATE_WIRED); 495 496 pgdir = page->physical_page_number * B_PAGE_SIZE; 497 498 TRACE(("map_tmap: asked for free page for pgdir. 0x%lx\n", pgdir)); 499 500 // for each pgdir on the allocated page: 501 for (i = 0; i < NUM_DIRTBL_PER_PAGE; i++) { 502 unsigned aindex = rindex & ~(NUM_DIRTBL_PER_PAGE-1); /* aligned */ 503 page_root_entry *apr = &pr[aindex + i]; 504 505 // put in the pgdir 506 put_pgdir_in_pgroot(apr, pgdir, attributes 507 | (attributes & B_USER_PROTECTION ? B_WRITE_AREA : B_KERNEL_WRITE_AREA)); 508 509 // update any other page directories, if it maps kernel space 510 //XXX: suboptimal, should batch them 511 if ((aindex+i) >= FIRST_KERNEL_PGDIR_ENT 512 && (aindex+i) < (FIRST_KERNEL_PGDIR_ENT + NUM_KERNEL_PGDIR_ENTS)) 513 _update_all_pgdirs((aindex+i), pr[aindex+i]); 514 515 pgdir += SIZ_DIRTBL; 516 } 517 #warning M68K: really mean map_count++ ?? 518 map->map_count++; 519 } 520 // now, fill in the pentry 521 do { 522 err = get_physical_page_tmap(PRE_TO_PA(pr[rindex]), 523 &pd_pg, PHYSICAL_PAGE_NO_WAIT); 524 } while (err < 0); 525 pd = (page_directory_entry *)pd_pg; 526 // we want the table at rindex, not at rindex%(tbl/page) 527 pd += (rindex % NUM_DIRTBL_PER_PAGE) * NUM_DIRENT_PER_TBL; 528 529 // check to see if a page table exists for this range 530 dindex = VADDR_TO_PDENT(va); 531 if (pd[dindex].type != DT_DIR) { 532 addr_t pgtable; 533 vm_page *page; 534 unsigned int i; 535 536 // we need to allocate a pgtable 537 page = vm_page_allocate_page(PAGE_STATE_CLEAR, true); 538 539 // mark the page WIRED 540 vm_page_set_state(page, PAGE_STATE_WIRED); 541 542 pgtable = page->physical_page_number * B_PAGE_SIZE; 543 544 TRACE(("map_tmap: asked for free page for pgtable. 0x%lx\n", pgtable)); 545 546 // for each pgtable on the allocated page: 547 for (i = 0; i < NUM_PAGETBL_PER_PAGE; i++) { 548 unsigned aindex = dindex & ~(NUM_PAGETBL_PER_PAGE-1); /* aligned */ 549 page_directory_entry *apd = &pd[aindex + i]; 550 551 // put in the pgdir 552 put_pgtable_in_pgdir(apd, pgtable, attributes 553 | (attributes & B_USER_PROTECTION ? B_WRITE_AREA : B_KERNEL_WRITE_AREA)); 554 555 // no need to update other page directories for kernel space; 556 // the root-level already point to us. 557 558 pgtable += SIZ_PAGETBL; 559 } 560 561 #warning M68K: really mean map_count++ ?? 562 map->map_count++; 563 } 564 // now, fill in the pentry 565 do { 566 err = get_physical_page_tmap(PDE_TO_PA(pd[dindex]), 567 &pt_pg, PHYSICAL_PAGE_NO_WAIT); 568 } while (err < 0); 569 pt = (page_table_entry *)pt_pg; 570 // we want the table at rindex, not at rindex%(tbl/page) 571 pt += (dindex % NUM_PAGETBL_PER_PAGE) * NUM_PAGEENT_PER_TBL; 572 573 pindex = VADDR_TO_PTENT(va); 574 575 put_page_table_entry_in_pgtable(&pt[pindex], pa, attributes, 576 IS_KERNEL_MAP(map)); 577 578 put_physical_page_tmap(pt_pg); 579 put_physical_page_tmap(pd_pg); 580 581 if (map->arch_data->num_invalidate_pages < PAGE_INVALIDATE_CACHE_SIZE) 582 map->arch_data->pages_to_invalidate[map->arch_data->num_invalidate_pages] = va; 583 584 map->arch_data->num_invalidate_pages++; 585 586 map->map_count++; 587 588 return 0; 589 } 590 591 592 static status_t 593 unmap_tmap(vm_translation_map *map, addr_t start, addr_t end) 594 { 595 page_table_entry *pt; 596 page_directory_entry *pd; 597 page_root_entry *pr = map->arch_data->rtdir_virt; 598 addr_t pd_pg, pt_pg; 599 status_t status; 600 int index; 601 602 start = ROUNDOWN(start, B_PAGE_SIZE); 603 end = ROUNDUP(end, B_PAGE_SIZE); 604 605 TRACE(("unmap_tmap: asked to free pages 0x%lx to 0x%lx\n", start, end)); 606 607 restart: 608 if (start >= end) 609 return B_OK; 610 611 index = VADDR_TO_PRENT(start); 612 if (pr[index].type != DT_ROOT) { 613 // no pagedir here, move the start up to access the next page table 614 start = ROUNDUP(start + 1, B_PAGE_SIZE); 615 goto restart; 616 } 617 618 do { 619 status = get_physical_page_tmap(PRE_TO_PA(pr[index]), 620 &pd_pg, PHYSICAL_PAGE_NO_WAIT); 621 } while (status < B_OK); 622 pd = (page_directory_entry *)pd_pg; 623 // we want the table at rindex, not at rindex%(tbl/page) 624 pd += (index % NUM_DIRTBL_PER_PAGE) * NUM_DIRENT_PER_TBL; 625 626 index = VADDR_TO_PDENT(start); 627 if (pd[index].type != DT_DIR) { 628 // no pagetable here, move the start up to access the next page table 629 start = ROUNDUP(start + 1, B_PAGE_SIZE); 630 put_physical_page_tmap(pd_pg); 631 goto restart; 632 } 633 634 do { 635 status = get_physical_page_tmap(PDE_TO_PA(pd[index]), 636 &pt_pg, PHYSICAL_PAGE_NO_WAIT); 637 } while (status < B_OK); 638 pt = (page_table_entry *)pt_pg; 639 // we want the table at rindex, not at rindex%(tbl/page) 640 pt += (index % NUM_PAGETBL_PER_PAGE) * NUM_PAGEENT_PER_TBL; 641 642 for (index = VADDR_TO_PTENT(start); 643 (index < NUM_PAGEENT_PER_TBL) && (start < end); 644 index++, start += B_PAGE_SIZE) { 645 if (pt[index].type != DT_PAGE && pt[index].type != DT_INDIRECT) { 646 // page mapping not valid 647 continue; 648 } 649 650 TRACE(("unmap_tmap: removing page 0x%lx\n", start)); 651 652 pt[index].type = DT_INVALID; 653 map->map_count--; 654 655 if (map->arch_data->num_invalidate_pages < PAGE_INVALIDATE_CACHE_SIZE) 656 map->arch_data->pages_to_invalidate[map->arch_data->num_invalidate_pages] = start; 657 658 map->arch_data->num_invalidate_pages++; 659 } 660 661 put_physical_page_tmap(pt_pg); 662 put_physical_page_tmap(pd_pg); 663 664 goto restart; 665 } 666 667 // XXX: 040 should be able to do that with PTEST (but not 030 or 060) 668 static status_t 669 query_tmap_interrupt(vm_translation_map *map, addr_t va, addr_t *_physical, 670 uint32 *_flags) 671 { 672 page_root_entry *pr = map->arch_data->rtdir_virt; 673 page_directory_entry *pd; 674 page_indirect_entry *pi; 675 page_table_entry *pt; 676 addr_t physicalPageTable; 677 int32 cpu = smp_get_current_cpu(); 678 int32 index; 679 status_t err = B_ERROR; // no pagetable here 680 681 if (sQueryPage == NULL) 682 return err; // not yet initialized !? 683 684 index = VADDR_TO_PRENT(va); 685 if (pr && pr[index].type == DT_ROOT) { 686 put_page_table_entry_in_pgtable(&sQueryDesc, PRE_TO_TA(pr[index]), B_KERNEL_READ_AREA, false); 687 invalidate_TLB(pt); 688 pd = (page_directory_entry *)sQueryPage; 689 index = VADDR_TO_PDENT(va); 690 691 if (pd && pd[index].type == DT_DIR) { 692 put_page_table_entry_in_pgtable(&sQueryDesc, PDE_TO_TA(pd[index]), B_KERNEL_READ_AREA, false); 693 invalidate_TLB(pt); 694 pt = (page_table_entry *)sQueryPage; 695 index = VADDR_TO_PTENT(va); 696 697 if (pt && pt[index].type == DT_INDIRECT) { 698 pi = pt; 699 put_page_table_entry_in_pgtable(&sQueryDesc, PIE_TO_TA(pi[index]), B_KERNEL_READ_AREA, false); 700 invalidate_TLB(pt); 701 pt = (page_table_entry *)sQueryPage; 702 index = 0; // single descriptor 703 } 704 705 if (pt /*&& pt[index].type == DT_PAGE*/) { 706 *_physical = PTE_TO_PA(pt[index]); 707 // we should only be passed page va, but just in case. 708 *_physical += va % B_PAGE_SIZE; 709 *_flags |= ((pt[index].write_protect ? 0 : B_KERNEL_WRITE_AREA : 0) | B_KERNEL_READ_AREA) 710 | (pt[index].dirty ? PAGE_MODIFIED : 0) 711 | (pt[index].accessed ? PAGE_ACCESSED : 0) 712 | ((pt[index].type == DT_PAGE) ? PAGE_PRESENT : 0); 713 err = B_OK; 714 } 715 } 716 717 // unmap the pg table from the indirect desc. 718 sQueryDesc.type = DT_INVALID; 719 720 return err; 721 } 722 723 724 static status_t 725 query_tmap(vm_translation_map *map, addr_t va, addr_t *_physical, uint32 *_flags) 726 { 727 page_table_entry *pt; 728 page_indirect_entry *pi; 729 page_directory_entry *pd; 730 page_directory_entry *pr = map->arch_data->rtdir_virt; 731 addr_t pd_pg, pt_pg, pi_pg; 732 status_t status; 733 int32 index; 734 735 // default the flags to not present 736 *_flags = 0; 737 *_physical = 0; 738 739 index = VADDR_TO_PRENT(va); 740 if (pr[index].type != DT_ROOT) { 741 // no pagetable here 742 return B_NO_ERROR; 743 } 744 745 do { 746 status = get_physical_page_tmap(PRE_TO_PA(pr[index]), 747 &pd_pg, PHYSICAL_PAGE_NO_WAIT); 748 } while (status < B_OK); 749 pd = (page_directory_entry *)pd_pg; 750 // we want the table at rindex, not at rindex%(tbl/page) 751 pd += (index % NUM_DIRTBL_PER_PAGE) * NUM_DIRENT_PER_TBL; 752 753 754 index = VADDR_TO_PDENT(start); 755 if (pd[index].type != DT_DIR) { 756 // no pagetable here 757 put_physical_page_tmap(pd_pg); 758 return B_NO_ERROR; 759 } 760 761 do { 762 status = get_physical_page_tmap(PDE_TO_PA(pd[index]), 763 &pt_pg, PHYSICAL_PAGE_NO_WAIT); 764 } while (status < B_OK); 765 pt = (page_table_entry *)pt_pg; 766 // we want the table at rindex, not at rindex%(tbl/page) 767 pt += (index % NUM_PAGETBL_PER_PAGE) * NUM_PAGEENT_PER_TBL; 768 769 index = VADDR_TO_PTENT(va); 770 771 // handle indirect descriptor 772 if (pt[index].type == DT_INDIRECT) { 773 pi = pt; 774 pi_pg = pt_pg; 775 do { 776 status = get_physical_page_tmap(PIE_TO_PA(pi[index]), 777 &pt_pg, PHYSICAL_PAGE_NO_WAIT); 778 } while (status < B_OK); 779 pt = (page_table_entry *)pt_pg; 780 // add offset from start of page 781 pt += PIE_TO_PO(pi[index]) / sizeof(page_table_entry); 782 // release the indirect table page 783 put_physical_page_tmap(pi_pg); 784 } 785 786 *_physical = PTE_TO_PA(pt[index]); 787 788 // read in the page state flags 789 if (!pt[index].supervisor) 790 *_flags |= (pt[index].write_protect ? 0 : B_WRITE_AREA) | B_READ_AREA; 791 792 *_flags |= (pt[index].write_protect ? 0 : B_KERNEL_WRITE_AREA) 793 | B_KERNEL_READ_AREA 794 | (pt[index].dirty ? PAGE_MODIFIED : 0) 795 | (pt[index].accessed ? PAGE_ACCESSED : 0) 796 | ((pt[index].type == DT_PAGE) ? PAGE_PRESENT : 0); 797 798 put_physical_page_tmap(pt_pg); 799 put_physical_page_tmap(pd_pg); 800 801 TRACE(("query_tmap: returning pa 0x%lx for va 0x%lx\n", *_physical, va)); 802 803 return B_OK; 804 } 805 806 807 static addr_t 808 get_mapped_size_tmap(vm_translation_map *map) 809 { 810 return map->map_count; 811 } 812 813 814 static status_t 815 protect_tmap(vm_translation_map *map, addr_t start, addr_t end, uint32 attributes) 816 { 817 page_table_entry *pt; 818 page_directory_entry *pd; 819 page_root_entry *pr = map->arch_data->rtdir_virt; 820 addr_t pd_pg, pt_pg; 821 status_t status; 822 int index; 823 824 start = ROUNDOWN(start, B_PAGE_SIZE); 825 end = ROUNDUP(end, B_PAGE_SIZE); 826 827 TRACE(("protect_tmap: pages 0x%lx to 0x%lx, attributes %lx\n", start, end, attributes)); 828 829 restart: 830 if (start >= end) 831 return B_OK; 832 833 index = VADDR_TO_PRENT(start); 834 if (pr[index].type != DT_ROOT) { 835 // no pagedir here, move the start up to access the next page table 836 start = ROUNDUP(start + 1, B_PAGE_SIZE); 837 goto restart; 838 } 839 840 do { 841 status = get_physical_page_tmap(PRE_TO_PA(pr[index]), 842 &pd_pg, PHYSICAL_PAGE_NO_WAIT); 843 } while (status < B_OK); 844 pd = (page_directory_entry *)pd_pg; 845 // we want the table at rindex, not at rindex%(tbl/page) 846 pd += (index % NUM_DIRTBL_PER_PAGE) * NUM_DIRENT_PER_TBL; 847 848 index = VADDR_TO_PDENT(start); 849 if (pd[index].type != DT_DIR) { 850 // no pagetable here, move the start up to access the next page table 851 start = ROUNDUP(start + 1, B_PAGE_SIZE); 852 put_physical_page_tmap(pd_pg); 853 goto restart; 854 } 855 856 do { 857 status = get_physical_page_tmap(PDE_TO_PA(pd[index]), 858 &pt_pg, PHYSICAL_PAGE_NO_WAIT); 859 } while (status < B_OK); 860 pt = (page_table_entry *)pt_pg; 861 // we want the table at rindex, not at rindex%(tbl/page) 862 pt += (index % NUM_PAGETBL_PER_PAGE) * NUM_PAGEENT_PER_TBL; 863 864 for (index = VADDR_TO_PTENT(start); 865 (index < NUM_PAGEENT_PER_TBL) && (start < end); 866 index++, start += B_PAGE_SIZE) { 867 // XXX: handle indirect ? 868 if (pt[index].type != DT_PAGE /*&& pt[index].type != DT_INDIRECT*/) { 869 // page mapping not valid 870 continue; 871 } 872 873 TRACE(("protect_tmap: protect page 0x%lx\n", start)); 874 875 pt[index].supervisor = (attributes & B_USER_PROTECTION) == 0; 876 if ((attributes & B_USER_PROTECTION) != 0) 877 pt[index].write_protect = (attributes & B_WRITE_AREA) == 0; 878 else 879 pt[index].write_protect = (attributes & B_KERNEL_WRITE_AREA) == 0; 880 881 if (map->arch_data->num_invalidate_pages < PAGE_INVALIDATE_CACHE_SIZE) 882 map->arch_data->pages_to_invalidate[map->arch_data->num_invalidate_pages] = start; 883 884 map->arch_data->num_invalidate_pages++; 885 } 886 887 put_physical_page_tmap(pt_pg); 888 put_physical_page_tmap(pd_pg); 889 890 goto restart; 891 } 892 893 894 static status_t 895 clear_flags_tmap(vm_translation_map *map, addr_t va, uint32 flags) 896 { 897 page_table_entry *pt; 898 page_indirect_entry *pi; 899 page_directory_entry *pd; 900 page_root_entry *pr = map->arch_data->rtdir_virt; 901 addr_t pd_pg, pt_pg, pi_pg; 902 status_t status; 903 int index; 904 int tlb_flush = false; 905 906 index = VADDR_TO_PRENT(va); 907 if (pr[index].type != DT_ROOT) { 908 // no pagetable here 909 return B_NO_ERROR; 910 } 911 912 do { 913 status = get_physical_page_tmap(PRE_TO_PA(pr[index]), 914 &pd_pg, PHYSICAL_PAGE_NO_WAIT); 915 } while (status < B_OK); 916 pd = (page_directory_entry *)pd_pg; 917 // we want the table at rindex, not at rindex%(tbl/page) 918 pd += (index % NUM_DIRTBL_PER_PAGE) * NUM_DIRENT_PER_TBL; 919 920 921 index = VADDR_TO_PDENT(start); 922 if (pd[index].type != DT_DIR) { 923 // no pagetable here 924 put_physical_page_tmap(pd_pg); 925 return B_NO_ERROR; 926 } 927 928 do { 929 status = get_physical_page_tmap(PDE_TO_PA(pd[index]), 930 &pt_pg, PHYSICAL_PAGE_NO_WAIT); 931 } while (status < B_OK); 932 pt = (page_table_entry *)pt_pg; 933 // we want the table at rindex, not at rindex%(tbl/page) 934 pt += (index % NUM_PAGETBL_PER_PAGE) * NUM_PAGEENT_PER_TBL; 935 936 index = VADDR_TO_PTENT(va); 937 938 // handle indirect descriptor 939 if (pt[index].type == DT_INDIRECT) { 940 pi = pt; 941 pi_pg = pt_pg; 942 do { 943 status = get_physical_page_tmap(PIE_TO_PA(pi[index]), 944 &pt_pg, PHYSICAL_PAGE_NO_WAIT); 945 } while (status < B_OK); 946 pt = (page_table_entry *)pt_pg; 947 // add offset from start of page 948 pt += PIE_TO_PO(pi[index]) / sizeof(page_table_entry); 949 // release the indirect table page 950 put_physical_page_tmap(pi_pg); 951 } 952 953 // clear out the flags we've been requested to clear 954 if (flags & PAGE_MODIFIED) { 955 pt[index].dirty = 0; 956 tlb_flush = true; 957 } 958 if (flags & PAGE_ACCESSED) { 959 pt[index].accessed = 0; 960 tlb_flush = true; 961 } 962 963 put_physical_page_tmap(pt_pg); 964 put_physical_page_tmap(pd_pg); 965 966 if (tlb_flush) { 967 if (map->arch_data->num_invalidate_pages < PAGE_INVALIDATE_CACHE_SIZE) 968 map->arch_data->pages_to_invalidate[map->arch_data->num_invalidate_pages] = va; 969 970 map->arch_data->num_invalidate_pages++; 971 } 972 973 return B_OK; 974 } 975 976 977 static void 978 flush_tmap(vm_translation_map *map) 979 { 980 cpu_status state; 981 982 if (map->arch_data->num_invalidate_pages <= 0) 983 return; 984 985 state = disable_interrupts(); 986 987 if (map->arch_data->num_invalidate_pages > PAGE_INVALIDATE_CACHE_SIZE) { 988 // invalidate all pages 989 TRACE(("flush_tmap: %d pages to invalidate, invalidate all\n", 990 map->arch_data->num_invalidate_pages)); 991 992 if (IS_KERNEL_MAP(map)) { 993 arch_cpu_global_TLB_invalidate(); 994 smp_send_broadcast_ici(SMP_MSG_GLOBAL_INVALIDATE_PAGES, 0, 0, 0, NULL, 995 SMP_MSG_FLAG_SYNC); 996 } else { 997 arch_cpu_user_TLB_invalidate(); 998 smp_send_broadcast_ici(SMP_MSG_USER_INVALIDATE_PAGES, 0, 0, 0, NULL, 999 SMP_MSG_FLAG_SYNC); 1000 } 1001 } else { 1002 TRACE(("flush_tmap: %d pages to invalidate, invalidate list\n", 1003 map->arch_data->num_invalidate_pages)); 1004 1005 arch_cpu_invalidate_TLB_list(map->arch_data->pages_to_invalidate, 1006 map->arch_data->num_invalidate_pages); 1007 smp_send_broadcast_ici(SMP_MSG_INVALIDATE_PAGE_LIST, 1008 (uint32)map->arch_data->pages_to_invalidate, 1009 map->arch_data->num_invalidate_pages, 0, NULL, 1010 SMP_MSG_FLAG_SYNC); 1011 } 1012 map->arch_data->num_invalidate_pages = 0; 1013 1014 restore_interrupts(state); 1015 } 1016 1017 1018 static status_t 1019 map_iospace_chunk(addr_t va, addr_t pa) 1020 { 1021 int i; 1022 page_table_entry *pt; 1023 int state; 1024 1025 pa &= ~(B_PAGE_SIZE - 1); // make sure it's page aligned 1026 va &= ~(B_PAGE_SIZE - 1); // make sure it's page aligned 1027 if (va < sIOSpaceBase || va >= (sIOSpaceBase + IOSPACE_SIZE)) 1028 panic("map_iospace_chunk: passed invalid va 0x%lx\n", va); 1029 1030 pt = &iospace_pgtables[(va - sIOSpaceBase) / B_PAGE_SIZE]; 1031 for (i = 0; i < 1024; i++, pa += B_PAGE_SIZE) { 1032 init_page_table_entry(&pt[i]); 1033 pt[i].addr = TA_TO_PTEA(pa); 1034 pt[i].supervisor = 1; 1035 pt[i].write_protect = 0; 1036 pt[i].type = DT_PAGE; 1037 // 040 or 060 only 1038 #ifdef MMU_HAS_GLOBAL_PAGES 1039 pt[i].global = 1; 1040 #endif 1041 } 1042 1043 state = disable_interrupts(); 1044 arch_cpu_invalidate_TLB_range(va, va + (IOSPACE_CHUNK_SIZE - B_PAGE_SIZE)); 1045 smp_send_broadcast_ici(SMP_MSG_INVALIDATE_PAGE_RANGE, 1046 va, va + (IOSPACE_CHUNK_SIZE - B_PAGE_SIZE), 0, 1047 NULL, SMP_MSG_FLAG_SYNC); 1048 restore_interrupts(state); 1049 1050 return B_OK; 1051 } 1052 1053 1054 static status_t 1055 get_physical_page_tmap(addr_t pa, addr_t *va, uint32 flags) 1056 { 1057 return generic_get_physical_page(pa, va, flags); 1058 } 1059 1060 1061 static status_t 1062 put_physical_page_tmap(addr_t va) 1063 { 1064 return generic_put_physical_page(va); 1065 } 1066 1067 1068 static vm_translation_map_ops tmap_ops = { 1069 destroy_tmap, 1070 lock_tmap, 1071 unlock_tmap, 1072 map_max_pages_need, 1073 map_tmap, 1074 unmap_tmap, 1075 query_tmap, 1076 query_tmap_interrupt, 1077 get_mapped_size_tmap, 1078 protect_tmap, 1079 clear_flags_tmap, 1080 flush_tmap, 1081 get_physical_page_tmap, 1082 put_physical_page_tmap 1083 }; 1084 1085 1086 // #pragma mark - 1087 // VM API 1088 1089 1090 static status_t 1091 arch_vm_translation_map_init_map(vm_translation_map *map, bool kernel) 1092 { 1093 if (map == NULL) 1094 return B_BAD_VALUE; 1095 1096 TRACE(("vm_translation_map_create\n")); 1097 1098 // initialize the new object 1099 map->ops = &tmap_ops; 1100 map->map_count = 0; 1101 1102 if (!kernel) { 1103 // During the boot process, there are no semaphores available at this 1104 // point, so we only try to create the translation map lock if we're 1105 // initialize a user translation map. 1106 // vm_translation_map_init_kernel_map_post_sem() is used to complete 1107 // the kernel translation map. 1108 if (recursive_lock_init(&map->lock, "translation map") < B_OK) 1109 return map->lock.sem; 1110 } 1111 1112 map->arch_data = (vm_translation_map_arch_info *)malloc(sizeof(vm_translation_map_arch_info)); 1113 if (map == NULL) { 1114 recursive_lock_destroy(&map->lock); 1115 return B_NO_MEMORY; 1116 } 1117 1118 map->arch_data->num_invalidate_pages = 0; 1119 1120 if (!kernel) { 1121 // user 1122 // allocate a rtdir 1123 map->arch_data->rtdir_virt = (page_root_entry *)memalign( 1124 SIZ_ROOTTBL, SIZ_ROOTTBL); 1125 if (map->arch_data->rtdir_virt == NULL) { 1126 free(map->arch_data); 1127 recursive_lock_destroy(&map->lock); 1128 return B_NO_MEMORY; 1129 } 1130 vm_get_page_mapping(vm_kernel_address_space_id(), 1131 (addr_t)map->arch_data->rtdir_virt, (addr_t *)&map->arch_data->rtdir_phys); 1132 } else { 1133 // kernel 1134 // we already know the kernel pgdir mapping 1135 map->arch_data->rtdir_virt = sKernelVirtualPageRoot; 1136 map->arch_data->rtdir_phys = sKernelPhysicalPageRoot; 1137 } 1138 1139 // zero out the bottom portion of the new rtdir 1140 memset(map->arch_data->rtdir_virt + FIRST_USER_PGROOT_ENT, 0, 1141 NUM_USER_PGROOT_ENTS * sizeof(page_root_entry)); 1142 1143 // insert this new map into the map list 1144 { 1145 int state = disable_interrupts(); 1146 acquire_spinlock(&tmap_list_lock); 1147 1148 // copy the top portion of the rtdir from the current one 1149 memcpy(map->arch_data->rtdir_virt + FIRST_KERNEL_PGROOT_ENT, 1150 sKernelVirtualPageRoot + FIRST_KERNEL_PGROOT_ENT, 1151 NUM_KERNEL_PGROOT_ENTS * sizeof(page_root_entry)); 1152 1153 map->next = tmap_list; 1154 tmap_list = map; 1155 1156 release_spinlock(&tmap_list_lock); 1157 restore_interrupts(state); 1158 } 1159 1160 return B_OK; 1161 } 1162 1163 1164 static status_t 1165 arch_vm_translation_map_init_kernel_map_post_sem(vm_translation_map *map) 1166 { 1167 if (recursive_lock_init(&map->lock, "translation map") < B_OK) 1168 return map->lock.sem; 1169 1170 return B_OK; 1171 } 1172 1173 1174 static status_t 1175 arch_vm_translation_map_init(kernel_args *args) 1176 { 1177 status_t error; 1178 1179 TRACE(("vm_translation_map_init: entry\n")); 1180 #if 0 1181 // page hole set up in stage2 1182 page_hole = (page_table_entry *)args->arch_args.page_hole; 1183 // calculate where the pgdir would be 1184 page_hole_pgdir = (page_directory_entry *)(((unsigned int)args->arch_args.page_hole) + (B_PAGE_SIZE * 1024 - B_PAGE_SIZE)); 1185 // clear out the bottom 2 GB, unmap everything 1186 memset(page_hole_pgdir + FIRST_USER_PGDIR_ENT, 0, sizeof(page_directory_entry) * NUM_USER_PGDIR_ENTS); 1187 #endif 1188 1189 sKernelPhysicalPageRoot = (page_root_entry *)args->arch_args.phys_pgroot; 1190 sKernelVirtualPageRoot = (page_root_entry *)args->arch_args.vir_pgroot; 1191 1192 sQueryDesc.type = DT_INVALID; 1193 1194 tmap_list_lock = 0; 1195 tmap_list = NULL; 1196 1197 // allocate some space to hold physical page mapping info 1198 //XXX: check page count 1199 #error XXXXXXXXXXXX pt + pd? pd = memalign ? 1200 iospace_pgtables = (page_table_entry *)vm_allocate_early(args, 1201 B_PAGE_SIZE * (IOSPACE_SIZE / (B_PAGE_SIZE * NUM_PAGEENT_PER_TBL * NUM_PAGETBL_PER_PAGE)), ~0L, 1202 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 1203 1204 TRACE(("iospace_pgtables %p\n", iospace_pgtables)); 1205 1206 // init physical page mapper 1207 error = generic_vm_physical_page_mapper_init(args, map_iospace_chunk, 1208 &sIOSpaceBase, IOSPACE_SIZE, IOSPACE_CHUNK_SIZE); 1209 if (error != B_OK) 1210 return error; 1211 1212 // initialize our data structures 1213 memset(iospace_pgtables, 0, B_PAGE_SIZE * (IOSPACE_SIZE / (B_PAGE_SIZE * 1024))); 1214 1215 TRACE(("mapping iospace_pgtables\n")); 1216 1217 // put the array of pgtables directly into the kernel pagedir 1218 // these will be wired and kept mapped into virtual space to be easy to get to 1219 { 1220 #error XXXXXXXXXXXX 1221 addr_t phys_pgtable; 1222 addr_t virt_pgtable; 1223 page_directory_entry *e; 1224 int i; 1225 1226 virt_pgtable = (addr_t)iospace_pgtables; 1227 for (i = 0; i < (IOSPACE_SIZE / (B_PAGE_SIZE * 1024)); i++, virt_pgtable += B_PAGE_SIZE) { 1228 early_query(virt_pgtable, &phys_pgtable); 1229 e = &page_hole_pgdir[(sIOSpaceBase / (B_PAGE_SIZE * 1024)) + i]; 1230 put_pgtable_in_pgdir(e, phys_pgtable, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 1231 } 1232 } 1233 1234 TRACE(("vm_translation_map_init: done\n")); 1235 1236 return B_OK; 1237 } 1238 1239 1240 static status_t 1241 arch_vm_translation_map_init_post_sem(kernel_args *args) 1242 { 1243 return generic_vm_physical_page_mapper_init_post_sem(args); 1244 } 1245 1246 1247 static status_t 1248 arch_vm_translation_map_init_post_area(kernel_args *args) 1249 { 1250 // now that the vm is initialized, create a region that represents 1251 // the page hole 1252 void *temp; 1253 status_t error; 1254 area_id area; 1255 void *queryPage; 1256 1257 TRACE(("vm_translation_map_init_post_area: entry\n")); 1258 1259 // unmap the page hole hack we were using before 1260 sKernelVirtualPageRoot[1023].present = 0; 1261 page_hole_pgdir = NULL; 1262 page_hole = NULL; 1263 1264 temp = (void *)sKernelVirtualPageRoot; 1265 area = create_area("kernel_pgdir", &temp, B_EXACT_ADDRESS, B_PAGE_SIZE, 1266 B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 1267 if (area < B_OK) 1268 return area; 1269 1270 temp = (void *)iospace_pgtables; 1271 area = create_area("iospace_pgtables", &temp, B_EXACT_ADDRESS, 1272 B_PAGE_SIZE * (IOSPACE_SIZE / (B_PAGE_SIZE * 1024)), 1273 B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 1274 if (area < B_OK) 1275 return area; 1276 1277 error = generic_vm_physical_page_mapper_init_post_area(args); 1278 if (error != B_OK) 1279 return error; 1280 1281 // this area is used for query_tmap_interrupt() 1282 // TODO: Note, this only works as long as all pages belong to the same 1283 // page table, which is not yet enforced (or even tested)! 1284 // Note we don't support SMP which makes things simpler. 1285 1286 area = vm_create_null_area(vm_kernel_address_space_id(), 1287 "interrupt query pages", (void **)&queryPage, B_ANY_ADDRESS, 1288 B_PAGE_SIZE); 1289 if (area < B_OK) 1290 return area; 1291 1292 // insert the indirect descriptor in the tree so we can map the page we want from it. 1293 1294 { 1295 page_directory_entry *pageDirEntry; 1296 page_indirect_entry *pageTableEntry; 1297 addr_t physicalPageDir, physicalPageTable; 1298 addr_t physicalIndirectDesc; 1299 int32 index; 1300 1301 // first get pa for the indirect descriptor 1302 1303 index = VADDR_TO_PRENT((addr_t)&sQueryDesc); 1304 physicalPageDir = PRE_TO_PA(sKernelVirtualPageRoot[index]); 1305 1306 get_physical_page_tmap(physicalPageDir, 1307 (addr_t *)&pageDirEntry, PHYSICAL_PAGE_NO_WAIT); 1308 1309 index = VADDR_TO_PDENT((addr_t)&sQueryDesc); 1310 physicalPageTable = PDE_TO_PA(pageDirEntry[index]); 1311 1312 get_physical_page_tmap(physicalPageTable, 1313 (addr_t *)&pageTableEntry, PHYSICAL_PAGE_NO_WAIT); 1314 1315 index = VADDR_TO_PTENT((addr_t)&sQueryDesc); 1316 1317 // pa of the page 1318 physicalIndirectDesc = PTE_TO_PA(pageTableEntry[index]); 1319 // add offset 1320 physicalIndirectDesc += ((addr_t)&sQueryDesc) % B_PAGE_SIZE; 1321 1322 put_physical_page_tmap((addr_t)pageTableEntry); 1323 put_physical_page_tmap((addr_t)pageDirEntry); 1324 1325 // then the va for the page table for the query page. 1326 1327 //sQueryPageTable = (page_indirect_entry *)(queryPage); 1328 1329 index = VADDR_TO_PRENT((addr_t)queryPage); 1330 physicalPageDir = PRE_TO_PA(sKernelVirtualPageRoot[index]); 1331 1332 get_physical_page_tmap(physicalPageDir, 1333 (addr_t *)&pageDirEntry, PHYSICAL_PAGE_NO_WAIT); 1334 1335 index = VADDR_TO_PDENT((addr_t)queryPage); 1336 physicalPageTable = PDE_TO_PA(pageDirEntry[index]); 1337 1338 get_physical_page_tmap(physicalPageTable, 1339 (addr_t *)&pageTableEntry, PHYSICAL_PAGE_NO_WAIT); 1340 1341 index = VADDR_TO_PTENT((addr_t)queryPage); 1342 1343 put_page_indirect_entry_in_pgtable(&pageTableEntry[index], physicalIndirectDesc, 1344 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, false); 1345 1346 put_physical_page_tmap((addr_t)pageTableEntry); 1347 put_physical_page_tmap((addr_t)pageDirEntry); 1348 //invalidate_TLB(sQueryPageTable); 1349 } 1350 // qmery_tmap_interrupt checks for the NULL, now it can use it 1351 sQueryPage = queryPage; 1352 1353 TRACE(("vm_translation_map_init_post_area: done\n")); 1354 return B_OK; 1355 } 1356 1357 1358 // XXX horrible back door to map a page quickly regardless of translation map object, etc. 1359 // used only during VM setup. 1360 // uses a 'page hole' set up in the stage 2 bootloader. The page hole is created by pointing one of 1361 // the pgdir entries back at itself, effectively mapping the contents of all of the 4MB of pagetables 1362 // into a 4 MB region. It's only used here, and is later unmapped. 1363 1364 static status_t 1365 arch_vm_translation_map_early_map(kernel_args *args, addr_t va, addr_t pa, 1366 uint8 attributes, addr_t (*get_free_page)(kernel_args *)) 1367 { 1368 int index; 1369 1370 TRACE(("early_tmap: entry pa 0x%lx va 0x%lx\n", pa, va)); 1371 1372 // check to see if a page table exists for this range 1373 index = VADDR_TO_PDENT(va); 1374 if (page_hole_pgdir[index].present == 0) { 1375 addr_t pgtable; 1376 page_directory_entry *e; 1377 // we need to allocate a pgtable 1378 pgtable = get_free_page(args); 1379 // pgtable is in pages, convert to physical address 1380 pgtable *= B_PAGE_SIZE; 1381 1382 TRACE(("early_map: asked for free page for pgtable. 0x%lx\n", pgtable)); 1383 1384 // put it in the pgdir 1385 e = &page_hole_pgdir[index]; 1386 put_pgtable_in_pgdir(e, pgtable, attributes); 1387 1388 // zero it out in it's new mapping 1389 memset((unsigned int *)((unsigned int)page_hole + (va / B_PAGE_SIZE / 1024) * B_PAGE_SIZE), 0, B_PAGE_SIZE); 1390 } 1391 1392 // now, fill in the pentry 1393 put_page_table_entry_in_pgtable(page_hole + va / B_PAGE_SIZE, pa, attributes, 1394 IS_KERNEL_ADDRESS(va)); 1395 1396 arch_cpu_invalidate_TLB_range(va, va); 1397 1398 return B_OK; 1399 } 1400 1401