1/* 2 * Copyright 2010, Ithamar R. Adema, ithamar.adema@team-embedded.nl 3 * Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8/*! Implementation of a physical page mapping strategy (PhysicalPageMapper, 9 TranslationMapPhysicalPageMapper) suitable for machines with a lot of 10 memory, i.e. more than we can afford to completely map into the kernel 11 address space. 12 13 We allocate a single page table (one page) that can map 1024 pages and 14 a corresponding virtual address space region (4 MB). Each of those 1024 15 slots can map a physical page. We reserve a fixed amount of slots per CPU. 16 They will be used for physical operations on that CPU (memset()/memcpy() 17 and {get,put}_physical_page_current_cpu()). A few slots we reserve for each 18 translation map (TranslationMapPhysicalPageMapper). Those will only be used 19 with the translation map locked, mapping a page table page. The remaining 20 slots remain in the global pool and are given out by get_physical_page(). 21 22 When we run out of slots, we allocate another page table (and virtual 23 address space region). 24*/ 25 26 27#include "paging/arm_physical_page_mapper_large_memory.h" 28 29#include <new> 30 31#include <AutoDeleter.h> 32 33#include <cpu.h> 34#include <lock.h> 35#include <smp.h> 36#include <util/AutoLock.h> 37#include <util/ThreadAutoLock.h> 38#include <vm/vm.h> 39#include <vm/vm_types.h> 40#include <vm/VMAddressSpace.h> 41 42#include "paging/arm_physical_page_mapper.h" 43#include "paging/ARMPagingStructures.h" 44#include "paging/ARMVMTranslationMap.h" 45 46 47// The number of slots we reserve per translation map from mapping page tables. 48// One slot would suffice, since the map is locked while mapping a page table, 49// but we re-use several slots on a LRU-basis so that we can keep the mappings 50// a little longer, thus avoiding re-mapping. 51#define SLOTS_PER_TRANSLATION_MAP 4 52 53 54 55using ARMLargePhysicalPageMapper::PhysicalPageSlot; 56using ARMLargePhysicalPageMapper::PhysicalPageSlotPool; 57 58 59class PhysicalPageSlotQueue { 60public: 61 PhysicalPageSlotQueue(); 62 63 inline PhysicalPageSlot* GetSlot(); 64 inline void GetSlots(PhysicalPageSlot*& slot1, 65 PhysicalPageSlot*& slot2); 66 inline void PutSlot(PhysicalPageSlot* slot); 67 inline void PutSlots(PhysicalPageSlot* slot1, 68 PhysicalPageSlot* slot2); 69 70private: 71 PhysicalPageSlot* fSlots; 72 ConditionVariable fFreeSlotCondition; 73 ConditionVariable fFreeSlotsCondition; 74}; 75 76 77struct PhysicalPageOpsCPUData { 78 PhysicalPageSlotQueue user; 79 // Used when copying from/to user memory. This can cause a page fault 80 // which might need to memcpy()/memset() a page when being handled. 81 PhysicalPageSlotQueue kernel; 82 // Used when memset()ing or when memcpy()ing memory non-user memory. 83 PhysicalPageSlot* interruptSlot; 84 85 void Init(); 86 87private: 88 static PhysicalPageSlot* _GetInitialSlot(); 89}; 90 91 92// #pragma mark - 93 94 95class LargeMemoryTranslationMapPhysicalPageMapper 96 : public TranslationMapPhysicalPageMapper { 97public: 98 LargeMemoryTranslationMapPhysicalPageMapper(); 99 virtual ~LargeMemoryTranslationMapPhysicalPageMapper(); 100 101 status_t Init(); 102 103 virtual void Delete(); 104 105 virtual void* GetPageTableAt(phys_addr_t physicalAddress); 106 107private: 108 struct page_slot { 109 PhysicalPageSlot* slot; 110 phys_addr_t physicalAddress; 111 CPUSet valid; 112 }; 113 114 page_slot fSlots[SLOTS_PER_TRANSLATION_MAP]; 115 int32 fSlotCount; // must be a power of 2 116 int32 fNextSlot; 117}; 118 119 120class LargeMemoryPhysicalPageMapper : public ARMPhysicalPageMapper { 121public: 122 LargeMemoryPhysicalPageMapper(); 123 124 status_t Init(kernel_args* args, 125 PhysicalPageSlotPool* initialPools, 126 int32 initalPoolCount, size_t poolSize, 127 TranslationMapPhysicalPageMapper*& 128 _kernelPageMapper); 129 130 virtual status_t CreateTranslationMapPhysicalPageMapper( 131 TranslationMapPhysicalPageMapper** _mapper); 132 133 virtual void* InterruptGetPageTableAt( 134 phys_addr_t physicalAddress); 135 136 virtual status_t GetPage(phys_addr_t physicalAddress, 137 addr_t* virtualAddress, void** handle); 138 virtual status_t PutPage(addr_t virtualAddress, void* handle); 139 140 virtual status_t GetPageCurrentCPU(phys_addr_t physicalAddress, 141 addr_t* virtualAddress, void** handle); 142 virtual status_t PutPageCurrentCPU(addr_t virtualAddress, 143 void* handle); 144 145 virtual status_t GetPageDebug(phys_addr_t physicalAddress, 146 addr_t* virtualAddress, void** handle); 147 virtual status_t PutPageDebug(addr_t virtualAddress, 148 void* handle); 149 150 virtual status_t MemsetPhysical(phys_addr_t address, int value, 151 phys_size_t length); 152 virtual status_t MemcpyFromPhysical(void* to, phys_addr_t from, 153 size_t length, bool user); 154 virtual status_t MemcpyToPhysical(phys_addr_t to, 155 const void* from, size_t length, bool user); 156 virtual void MemcpyPhysicalPage(phys_addr_t to, 157 phys_addr_t from); 158 159 status_t GetSlot(bool canWait, 160 PhysicalPageSlot*& slot); 161 void PutSlot(PhysicalPageSlot* slot); 162 163 inline PhysicalPageSlotQueue* GetSlotQueue(int32 cpu, bool user); 164 165private: 166 typedef DoublyLinkedList<PhysicalPageSlotPool> PoolList; 167 168 mutex fLock; 169 PoolList fEmptyPools; 170 PoolList fNonEmptyPools; 171 PhysicalPageSlot* fDebugSlot; 172 PhysicalPageSlotPool* fInitialPool; 173 LargeMemoryTranslationMapPhysicalPageMapper fKernelMapper; 174 PhysicalPageOpsCPUData fPerCPUData[SMP_MAX_CPUS]; 175}; 176 177static LargeMemoryPhysicalPageMapper sPhysicalPageMapper; 178 179 180// #pragma mark - PhysicalPageSlot / PhysicalPageSlotPool 181 182 183inline void 184PhysicalPageSlot::Map(phys_addr_t physicalAddress) 185{ 186 pool->Map(physicalAddress, address); 187} 188 189 190PhysicalPageSlotPool::~PhysicalPageSlotPool() 191{ 192} 193 194 195inline bool 196PhysicalPageSlotPool::IsEmpty() const 197{ 198 return fSlots == NULL; 199} 200 201 202inline PhysicalPageSlot* 203PhysicalPageSlotPool::GetSlot() 204{ 205 PhysicalPageSlot* slot = fSlots; 206 fSlots = slot->next; 207 return slot; 208} 209 210 211inline void 212PhysicalPageSlotPool::PutSlot(PhysicalPageSlot* slot) 213{ 214 slot->next = fSlots; 215 fSlots = slot; 216} 217 218 219// #pragma mark - PhysicalPageSlotQueue 220 221 222PhysicalPageSlotQueue::PhysicalPageSlotQueue() 223 : 224 fSlots(NULL) 225{ 226 fFreeSlotCondition.Init(this, "physical page ops slot queue"); 227 fFreeSlotsCondition.Init(this, "physical page ops slots queue"); 228} 229 230 231PhysicalPageSlot* 232PhysicalPageSlotQueue::GetSlot() 233{ 234 InterruptsLocker locker; 235 236 // wait for a free slot to turn up 237 while (fSlots == NULL) { 238 ConditionVariableEntry entry; 239 fFreeSlotCondition.Add(&entry); 240 locker.Unlock(); 241 entry.Wait(); 242 locker.Lock(); 243 } 244 245 PhysicalPageSlot* slot = fSlots; 246 fSlots = slot->next; 247 248 return slot; 249} 250 251 252void 253PhysicalPageSlotQueue::GetSlots(PhysicalPageSlot*& slot1, 254 PhysicalPageSlot*& slot2) 255{ 256 InterruptsLocker locker; 257 258 // wait for two free slot to turn up 259 while (fSlots == NULL || fSlots->next == NULL) { 260 ConditionVariableEntry entry; 261 fFreeSlotsCondition.Add(&entry); 262 locker.Unlock(); 263 entry.Wait(); 264 locker.Lock(); 265 } 266 267 slot1 = fSlots; 268 slot2 = slot1->next; 269 fSlots = slot2->next; 270} 271 272 273void 274PhysicalPageSlotQueue::PutSlot(PhysicalPageSlot* slot) 275{ 276 InterruptsLocker locker; 277 278 slot->next = fSlots; 279 fSlots = slot; 280 281 if (slot->next == NULL) 282 fFreeSlotCondition.NotifyAll(); 283 else if (slot->next->next == NULL) 284 fFreeSlotCondition.NotifyAll(); 285} 286 287 288void 289PhysicalPageSlotQueue::PutSlots(PhysicalPageSlot* slot1, 290 PhysicalPageSlot* slot2) 291{ 292 InterruptsLocker locker; 293 294 slot1->next = slot2; 295 slot2->next = fSlots; 296 fSlots = slot1; 297 298 if (slot2->next == NULL) 299 fFreeSlotCondition.NotifyAll(); 300 else if (slot2->next->next == NULL) 301 fFreeSlotCondition.NotifyAll(); 302} 303 304 305// #pragma mark - PhysicalPageOpsCPUData 306 307 308void 309PhysicalPageOpsCPUData::Init() 310{ 311 for (int32 i = 0; i < USER_SLOTS_PER_CPU; i++) 312 user.PutSlot(_GetInitialSlot()); 313 for (int32 i = 0; i < KERNEL_SLOTS_PER_CPU; i++) 314 kernel.PutSlot(_GetInitialSlot()); 315 interruptSlot = _GetInitialSlot(); 316} 317 318 319/* static */ PhysicalPageSlot* 320PhysicalPageOpsCPUData::_GetInitialSlot() 321{ 322 PhysicalPageSlot* slot; 323 status_t error = sPhysicalPageMapper.GetSlot(false, slot); 324 if (error != B_OK) { 325 panic("PhysicalPageOpsCPUData::Init(): Failed to get initial " 326 "physical page slots! Probably too many CPUs."); 327 return NULL; 328 } 329 330 return slot; 331} 332 333 334// #pragma mark - LargeMemoryTranslationMapPhysicalPageMapper 335 336 337LargeMemoryTranslationMapPhysicalPageMapper 338 ::LargeMemoryTranslationMapPhysicalPageMapper() 339 : 340 fSlotCount(sizeof(fSlots) / sizeof(page_slot)), 341 fNextSlot(0) 342{ 343 memset(fSlots, 0, sizeof(fSlots)); 344} 345 346 347LargeMemoryTranslationMapPhysicalPageMapper 348 ::~LargeMemoryTranslationMapPhysicalPageMapper() 349{ 350 // put our slots back to the global pool 351 for (int32 i = 0; i < fSlotCount; i++) { 352 if (fSlots[i].slot != NULL) 353 sPhysicalPageMapper.PutSlot(fSlots[i].slot); 354 } 355} 356 357 358status_t 359LargeMemoryTranslationMapPhysicalPageMapper::Init() 360{ 361 // get our slots from the global pool 362 for (int32 i = 0; i < fSlotCount; i++) { 363 status_t error = sPhysicalPageMapper.GetSlot(true, fSlots[i].slot); 364 if (error != B_OK) 365 return error; 366 367 // set to invalid physical address, so it won't be used accidentally 368 fSlots[i].physicalAddress = ~(phys_addr_t)0; 369 } 370 371 return B_OK; 372} 373 374 375void 376LargeMemoryTranslationMapPhysicalPageMapper::Delete() 377{ 378 delete this; 379} 380 381 382void* 383LargeMemoryTranslationMapPhysicalPageMapper::GetPageTableAt( 384 phys_addr_t physicalAddress) 385{ 386 phys_addr_t off = physicalAddress & (B_PAGE_SIZE -1); 387 physicalAddress &= ~(B_PAGE_SIZE -1); 388 389 int32 currentCPU = smp_get_current_cpu(); 390 391 // maybe the address is already mapped 392 for (int32 i = 0; i < fSlotCount; i++) { 393 page_slot& slot = fSlots[i]; 394 if (slot.physicalAddress == physicalAddress) { 395 fNextSlot = (i + 1) & (fSlotCount - 1); 396 if (!slot.valid.GetBit(currentCPU)) { 397 // not valid on this CPU -- invalidate the TLB entry 398 arch_cpu_invalidate_TLB_range(slot.slot->address, 399 slot.slot->address + B_PAGE_SIZE); 400 slot.valid.SetBit(currentCPU); 401 } 402 return (uint8*)slot.slot->address + off; 403 } 404 } 405 406 // not found -- need to map a fresh one 407 page_slot& slot = fSlots[fNextSlot]; 408 fNextSlot = (fNextSlot + 1) & (fSlotCount - 1); 409 410 slot.physicalAddress = physicalAddress; 411 slot.slot->Map(physicalAddress); 412 slot.valid.ClearAll(); 413 slot.valid.SetBit(currentCPU); 414 415 return (uint8*)slot.slot->address + off; 416} 417 418 419// #pragma mark - LargeMemoryPhysicalPageMapper 420 421 422LargeMemoryPhysicalPageMapper::LargeMemoryPhysicalPageMapper() 423 : 424 fInitialPool(NULL) 425{ 426 mutex_init(&fLock, "large memory physical page mapper"); 427} 428 429 430status_t 431LargeMemoryPhysicalPageMapper::Init(kernel_args* args, 432 PhysicalPageSlotPool* initialPools, int32 initialPoolCount, size_t poolSize, 433 TranslationMapPhysicalPageMapper*& _kernelPageMapper) 434{ 435 ASSERT(initialPoolCount >= 1); 436 437 fInitialPool = initialPools; 438 for (int32 i = 0; i < initialPoolCount; i++) { 439 uint8* pointer = (uint8*)initialPools + i * poolSize; 440 fNonEmptyPools.Add((PhysicalPageSlotPool*)pointer); 441 } 442 443 // get the debug slot 444 GetSlot(true, fDebugSlot); 445 446 // init the kernel translation map physical page mapper 447 status_t error = fKernelMapper.Init(); 448 if (error != B_OK) { 449 panic("LargeMemoryPhysicalPageMapper::Init(): Failed to init " 450 "kernel translation map physical page mapper!"); 451 return error; 452 } 453 _kernelPageMapper = &fKernelMapper; 454 455 // init the per-CPU data 456 int32 cpuCount = smp_get_num_cpus(); 457 for (int32 i = 0; i < cpuCount; i++) 458 fPerCPUData[i].Init(); 459 460 return B_OK; 461} 462 463 464status_t 465LargeMemoryPhysicalPageMapper::CreateTranslationMapPhysicalPageMapper( 466 TranslationMapPhysicalPageMapper** _mapper) 467{ 468 LargeMemoryTranslationMapPhysicalPageMapper* mapper 469 = new(std::nothrow) LargeMemoryTranslationMapPhysicalPageMapper; 470 if (mapper == NULL) 471 return B_NO_MEMORY; 472 473 status_t error = mapper->Init(); 474 if (error != B_OK) { 475 delete mapper; 476 return error; 477 } 478 479 *_mapper = mapper; 480 return B_OK; 481} 482 483 484void* 485LargeMemoryPhysicalPageMapper::InterruptGetPageTableAt( 486 phys_addr_t physicalAddress) 487{ 488 phys_addr_t off = physicalAddress & (B_PAGE_SIZE -1); 489 physicalAddress &= ~(B_PAGE_SIZE -1); 490 491 PhysicalPageSlot* slot = fPerCPUData[smp_get_current_cpu()].interruptSlot; 492 slot->Map(physicalAddress); 493 return (void*)slot->address + off; 494} 495 496 497status_t 498LargeMemoryPhysicalPageMapper::GetPage(phys_addr_t physicalAddress, 499 addr_t* virtualAddress, void** handle) 500{ 501 PhysicalPageSlot* slot; 502 status_t error = GetSlot(true, slot); 503 if (error != B_OK) 504 return error; 505 506 slot->Map(physicalAddress); 507 508 *handle = slot; 509 *virtualAddress = slot->address + physicalAddress % B_PAGE_SIZE; 510 511 smp_send_broadcast_ici(SMP_MSG_INVALIDATE_PAGE_RANGE, *virtualAddress, 512 *virtualAddress, 0, NULL, SMP_MSG_FLAG_SYNC); 513 514 return B_OK; 515} 516 517 518status_t 519LargeMemoryPhysicalPageMapper::PutPage(addr_t virtualAddress, void* handle) 520{ 521 PutSlot((PhysicalPageSlot*)handle); 522 return B_OK; 523} 524 525 526status_t 527LargeMemoryPhysicalPageMapper::GetPageCurrentCPU(phys_addr_t physicalAddress, 528 addr_t* virtualAddress, void** handle) 529{ 530 // get a slot from the per-cpu user pool 531 PhysicalPageSlotQueue& slotQueue 532 = fPerCPUData[smp_get_current_cpu()].user; 533 PhysicalPageSlot* slot = slotQueue.GetSlot(); 534 slot->Map(physicalAddress); 535 536 *virtualAddress = slot->address + physicalAddress % B_PAGE_SIZE; 537 *handle = slot; 538 539 return B_OK; 540} 541 542 543status_t 544LargeMemoryPhysicalPageMapper::PutPageCurrentCPU(addr_t virtualAddress, 545 void* handle) 546{ 547 // return the slot to the per-cpu user pool 548 PhysicalPageSlotQueue& slotQueue 549 = fPerCPUData[smp_get_current_cpu()].user; 550 slotQueue.PutSlot((PhysicalPageSlot*)handle); 551 return B_OK; 552} 553 554 555status_t 556LargeMemoryPhysicalPageMapper::GetPageDebug(phys_addr_t physicalAddress, 557 addr_t* virtualAddress, void** handle) 558{ 559 fDebugSlot->Map(physicalAddress); 560 561 *handle = fDebugSlot; 562 *virtualAddress = fDebugSlot->address + physicalAddress % B_PAGE_SIZE; 563 return B_OK; 564} 565 566 567status_t 568LargeMemoryPhysicalPageMapper::PutPageDebug(addr_t virtualAddress, void* handle) 569{ 570 return B_OK; 571} 572 573 574status_t 575LargeMemoryPhysicalPageMapper::MemsetPhysical(phys_addr_t address, int value, 576 phys_size_t length) 577{ 578 addr_t pageOffset = address % B_PAGE_SIZE; 579 580 Thread* thread = thread_get_current_thread(); 581 ThreadCPUPinner _(thread); 582 583 PhysicalPageSlotQueue* slotQueue = GetSlotQueue(thread->cpu->cpu_num, 584 false); 585 PhysicalPageSlot* slot = slotQueue->GetSlot(); 586 587 while (length > 0) { 588 slot->Map(address - pageOffset); 589 590 size_t toSet = min_c(length, B_PAGE_SIZE - pageOffset); 591 memset((void*)(slot->address + pageOffset), value, toSet); 592 593 length -= toSet; 594 address += toSet; 595 pageOffset = 0; 596 } 597 598 slotQueue->PutSlot(slot); 599 600 return B_OK; 601} 602 603 604status_t 605LargeMemoryPhysicalPageMapper::MemcpyFromPhysical(void* _to, phys_addr_t from, 606 size_t length, bool user) 607{ 608 uint8* to = (uint8*)_to; 609 addr_t pageOffset = from % B_PAGE_SIZE; 610 611 Thread* thread = thread_get_current_thread(); 612 ThreadCPUPinner _(thread); 613 614 PhysicalPageSlotQueue* slotQueue = GetSlotQueue(thread->cpu->cpu_num, user); 615 PhysicalPageSlot* slot = slotQueue->GetSlot(); 616 617 status_t error = B_OK; 618 619 while (length > 0) { 620 size_t toCopy = min_c(length, B_PAGE_SIZE - pageOffset); 621 622 slot->Map(from - pageOffset); 623 624 if (user) { 625 error = user_memcpy(to, (void*)(slot->address + pageOffset), 626 toCopy); 627 if (error != B_OK) 628 break; 629 } else 630 memcpy(to, (void*)(slot->address + pageOffset), toCopy); 631 632 to += toCopy; 633 from += toCopy; 634 length -= toCopy; 635 pageOffset = 0; 636 } 637 638 slotQueue->PutSlot(slot); 639 640 return error; 641} 642 643 644status_t 645LargeMemoryPhysicalPageMapper::MemcpyToPhysical(phys_addr_t to, 646 const void* _from, size_t length, bool user) 647{ 648 const uint8* from = (const uint8*)_from; 649 addr_t pageOffset = to % B_PAGE_SIZE; 650 651 Thread* thread = thread_get_current_thread(); 652 ThreadCPUPinner _(thread); 653 654 PhysicalPageSlotQueue* slotQueue = GetSlotQueue(thread->cpu->cpu_num, user); 655 PhysicalPageSlot* slot = slotQueue->GetSlot(); 656 657 status_t error = B_OK; 658 659 while (length > 0) { 660 size_t toCopy = min_c(length, B_PAGE_SIZE - pageOffset); 661 662 slot->Map(to - pageOffset); 663 664 if (user) { 665 error = user_memcpy((void*)(slot->address + pageOffset), from, 666 toCopy); 667 if (error != B_OK) 668 break; 669 } else 670 memcpy((void*)(slot->address + pageOffset), from, toCopy); 671 672 to += toCopy; 673 from += toCopy; 674 length -= toCopy; 675 pageOffset = 0; 676 } 677 678 slotQueue->PutSlot(slot); 679 680 return error; 681} 682 683 684void 685LargeMemoryPhysicalPageMapper::MemcpyPhysicalPage(phys_addr_t to, 686 phys_addr_t from) 687{ 688 Thread* thread = thread_get_current_thread(); 689 ThreadCPUPinner _(thread); 690 691 PhysicalPageSlotQueue* slotQueue = GetSlotQueue(thread->cpu->cpu_num, 692 false); 693 PhysicalPageSlot* fromSlot; 694 PhysicalPageSlot* toSlot; 695 slotQueue->GetSlots(fromSlot, toSlot); 696 697 fromSlot->Map(from); 698 toSlot->Map(to); 699 700 memcpy((void*)toSlot->address, (void*)fromSlot->address, B_PAGE_SIZE); 701 702 slotQueue->PutSlots(fromSlot, toSlot); 703} 704 705 706status_t 707LargeMemoryPhysicalPageMapper::GetSlot(bool canWait, PhysicalPageSlot*& slot) 708{ 709 MutexLocker locker(fLock); 710 711 PhysicalPageSlotPool* pool = fNonEmptyPools.Head(); 712 if (pool == NULL) { 713 if (!canWait) 714 return B_WOULD_BLOCK; 715 716 // allocate new pool 717 locker.Unlock(); 718 status_t error = fInitialPool->AllocatePool(pool); 719 if (error != B_OK) 720 return error; 721 locker.Lock(); 722 723 fNonEmptyPools.Add(pool); 724 pool = fNonEmptyPools.Head(); 725 } 726 727 slot = pool->GetSlot(); 728 729 if (pool->IsEmpty()) { 730 fNonEmptyPools.Remove(pool); 731 fEmptyPools.Add(pool); 732 } 733 734 return B_OK; 735} 736 737 738void 739LargeMemoryPhysicalPageMapper::PutSlot(PhysicalPageSlot* slot) 740{ 741 MutexLocker locker(fLock); 742 743 PhysicalPageSlotPool* pool = slot->pool; 744 if (pool->IsEmpty()) { 745 fEmptyPools.Remove(pool); 746 fNonEmptyPools.Add(pool); 747 } 748 749 pool->PutSlot(slot); 750} 751 752 753inline PhysicalPageSlotQueue* 754LargeMemoryPhysicalPageMapper::GetSlotQueue(int32 cpu, bool user) 755{ 756 return user ? &fPerCPUData[cpu].user : &fPerCPUData[cpu].kernel; 757} 758 759 760// #pragma mark - Initialization 761 762 763status_t 764large_memory_physical_page_ops_init(kernel_args* args, 765 ARMLargePhysicalPageMapper::PhysicalPageSlotPool* initialPools, 766 int32 initialPoolCount, size_t poolSize, 767 ARMPhysicalPageMapper*& _pageMapper, 768 TranslationMapPhysicalPageMapper*& _kernelPageMapper) 769{ 770 new(&sPhysicalPageMapper) LargeMemoryPhysicalPageMapper; 771 sPhysicalPageMapper.Init(args, initialPools, initialPoolCount, poolSize, 772 _kernelPageMapper); 773 774 _pageMapper = &sPhysicalPageMapper; 775 return B_OK; 776} 777