1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: BSD - See COPYING.ARM in the top level directory 4 * FILE: ntoskrnl/mm/arm/stubs.c 5 * PURPOSE: ARM Memory Manager 6 * PROGRAMMERS: ReactOS Portable Systems Group 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include <ntoskrnl.h> 12 #define NDEBUG 13 #include <debug.h> 14 15 /* GLOBALS ********************************************************************/ 16 17 ULONG MmGlobalKernelPageDirectory[1024]; 18 MMPTE MiArmTemplatePte; 19 MMPDE_HARDWARE MiArmTemplatePde; 20 21 /* PRIVATE FUNCTIONS **********************************************************/ 22 23 BOOLEAN 24 NTAPI 25 MiUnmapPageTable(IN PMMPTE PointerPde) 26 { 27 // 28 // Check if this address belongs to the kernel 29 // 30 if (((ULONG_PTR)PointerPde > PDE_BASE) || 31 ((ULONG_PTR)PointerPde < (PDE_BASE + 1024*1024))) 32 { 33 // 34 // Nothing to do 35 // 36 return TRUE; 37 } 38 39 // 40 // FIXME-USER: Shouldn't get here yet 41 // 42 ERROR_FATAL(); 43 return FALSE; 44 } 45 46 VOID 47 NTAPI 48 MiFlushTlb(IN PMMPTE PointerPte, 49 IN PVOID Address) 50 { 51 // 52 // Make sure the PTE is valid, and unmap the pagetable if user-mode 53 // 54 if (((PointerPte) && (MiUnmapPageTable(PointerPte))) || 55 (Address >= MmSystemRangeStart)) 56 { 57 // 58 // Invalidate this page 59 // 60 KeArmInvalidateTlbEntry(Address); 61 } 62 } 63 64 PMMPTE 65 NTAPI 66 MiGetPageTableForProcess(IN PEPROCESS Process, 67 IN PVOID Address, 68 IN BOOLEAN Create) 69 { 70 //ULONG PdeOffset; 71 PMMPTE PointerPte; 72 PMMPDE_HARDWARE PointerPde; 73 MMPDE_HARDWARE TempPde; 74 MMPTE TempPte; 75 NTSTATUS Status; 76 PFN_NUMBER Pfn; 77 78 // 79 // Check if this is a user-mode, non-kernel or non-current address 80 // 81 if ((Address < MmSystemRangeStart) && 82 (Process) && 83 (Process != PsGetCurrentProcess())) 84 { 85 // 86 // FIXME-USER: No user-mode memory support 87 // 88 ASSERT(FALSE); 89 } 90 91 // 92 // Get our templates 93 // 94 TempPde = MiArmTemplatePde; 95 TempPte = MiArmTemplatePte; 96 97 // 98 // Get the PDE 99 // 100 PointerPde = MiAddressToPde(Address); 101 if (PointerPde->u.Hard.Coarse.Valid) 102 { 103 // 104 // Invalid PDE, is this a kernel address? 105 // 106 if (Address >= MmSystemRangeStart) 107 { 108 // 109 // Does it exist in the kernel page directory? 110 // 111 //PdeOffset = MiGetPdeOffset(Address); 112 //if (MmGlobalKernelPageDirectory[PdeOffset] == 0) 113 { 114 // 115 // It doesn't. Is this a create operation? If not, fail 116 // 117 if (Create == FALSE) return NULL; 118 kernelHack: 119 DPRINT1("Must create a page for: %p PDE: %p\n", // Offset: %lx!\n", 120 Address, PointerPde);//, PdeOffset); 121 122 // 123 // Allocate a non paged pool page for the PDE 124 // 125 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn); 126 if (!NT_SUCCESS(Status)) return NULL; 127 128 // 129 // Setup the PFN 130 // 131 TempPde.u.Hard.Coarse.PageFrameNumber = (Pfn << PAGE_SHIFT) >> CPT_SHIFT; 132 133 // 134 // Write the PDE 135 // 136 ASSERT(PointerPde->u.Hard.Coarse.Valid == 0); 137 ASSERT(TempPde.u.Hard.Coarse.Valid == 1); 138 *PointerPde = TempPde; 139 140 // 141 // Save it 142 // 143 //MmGlobalKernelPageDirectory[PdeOffset] = TempPde.u.Hard.AsUlong; 144 //DPRINT1("KPD: %p PDEADDR: %p\n", &MmGlobalKernelPageDirectory[PdeOffset], MiAddressToPde(Address)); 145 146 // 147 // FIXFIX: Double check with Felix tomorrow 148 // 149 ///// 150 // 151 // Get the PTE for this 1MB region 152 // 153 PointerPte = MiAddressToPte(MiAddressToPte(Address)); 154 DPRINT1("PointerPte: %p\n", PointerPte); 155 156 // 157 // Write the PFN of the PDE 158 // 159 TempPte.u.Hard.PageFrameNumber = Pfn; 160 161 // 162 // Write the PTE 163 // 164 ASSERT(PointerPte->u.Hard.Valid == 0); 165 ASSERT(TempPte.u.Hard.Valid == 1); 166 *PointerPte = TempPte; 167 ///// 168 } 169 170 // 171 // Now set the actual PDE 172 // 173 //PointerPde = (PMMPTE)&MmGlobalKernelPageDirectory[PdeOffset]; 174 } 175 else 176 { 177 // 178 // Is this a create operation? If not, fail 179 // 180 if (Create == FALSE) return NULL; 181 182 // 183 // THIS WHOLE PATH IS TODO 184 // 185 #if 1 186 goto kernelHack; 187 #else 188 ASSERT(FALSE); 189 190 // 191 // Allocate a non paged pool page for the PDE 192 // 193 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn); 194 if (!NT_SUCCESS(Status)) return NULL; 195 196 // 197 // Make the entry valid 198 // 199 TempPde.u.Hard.AsUlong = 0xDEADBEEF; 200 201 // 202 // Set it 203 // 204 *PointerPde = TempPde; 205 #endif 206 } 207 } 208 209 // 210 // Return the PTE 211 // 212 return MiAddressToPte(Address); 213 } 214 215 MMPTE 216 NTAPI 217 MiGetPageEntryForProcess(IN PEPROCESS Process, 218 IN PVOID Address) 219 { 220 PMMPTE PointerPte; 221 MMPTE Pte; 222 Pte.u.Hard.AsUlong = 0; 223 224 // 225 // Get the PTE 226 // 227 PointerPte = MiGetPageTableForProcess(Process, Address, FALSE); 228 if (PointerPte) 229 { 230 // 231 // Capture the PTE value and unmap the page table 232 // 233 Pte = *PointerPte; 234 MiUnmapPageTable(PointerPte); 235 } 236 237 // 238 // Return the PTE value 239 // 240 return Pte; 241 } 242 243 BOOLEAN 244 NTAPI 245 MmCreateProcessAddressSpace(IN ULONG MinWs, 246 IN PEPROCESS Process, 247 IN PULONG DirectoryTableBase) 248 { 249 NTSTATUS Status; 250 ULONG i; 251 PFN_NUMBER Pfn[2]; 252 PMMPDE_HARDWARE PageDirectory, PointerPde; 253 MMPDE_HARDWARE TempPde; 254 ASSERT(FALSE); 255 256 // 257 // Loop two tables (Hyperspace and TTB). Each one is 16KB 258 // 259 // 260 for (i = 0; i < sizeof(Pfn) / sizeof(Pfn[0]); i++) 261 { 262 // 263 // Allocate a page 264 // 265 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn[i]); 266 if (!NT_SUCCESS(Status)) ASSERT(FALSE); 267 } 268 269 // 270 // Map the base 271 // 272 PageDirectory = MmCreateHyperspaceMapping(Pfn[0]); 273 274 // 275 // Copy the PDEs for kernel-mode 276 // 277 RtlCopyMemory(PageDirectory + MiGetPdeOffset(MmSystemRangeStart), 278 MmGlobalKernelPageDirectory + MiGetPdeOffset(MmSystemRangeStart), 279 (1024 - MiGetPdeOffset(MmSystemRangeStart)) * sizeof(ULONG)); 280 281 282 // 283 // Setup the PDE for the table base 284 // 285 TempPde = MiArmTemplatePde; 286 TempPde.u.Hard.Coarse.PageFrameNumber = (Pfn[0] << PAGE_SHIFT) >> CPT_SHIFT; 287 PointerPde = &PageDirectory[MiGetPdeOffset(PTE_BASE)]; 288 289 // 290 // Write the PDE 291 // 292 ASSERT(PointerPde->u.Hard.Coarse.Valid == 0); 293 ASSERT(TempPde.u.Hard.Coarse.Valid == 1); 294 *PointerPde = TempPde; 295 296 // 297 // Setup the PDE for the hyperspace 298 // 299 TempPde.u.Hard.Coarse.PageFrameNumber = (Pfn[1] << PAGE_SHIFT) >> CPT_SHIFT; 300 PointerPde = &PageDirectory[MiGetPdeOffset(HYPER_SPACE)]; 301 302 // 303 // Write the PDE 304 // 305 ASSERT(PointerPde->u.Hard.Coarse.Valid == 0); 306 ASSERT(TempPde.u.Hard.Coarse.Valid == 1); 307 *PointerPde = TempPde; 308 309 // 310 // Unmap the page directory 311 // 312 MmDeleteHyperspaceMapping(PageDirectory); 313 314 // 315 // Return the page table base 316 // 317 DirectoryTableBase[0] = Pfn[0] << PAGE_SHIFT; 318 return TRUE; 319 } 320 321 NTSTATUS 322 NTAPI 323 MmCreateVirtualMappingInternal(IN PEPROCESS Process, 324 IN PVOID Address, 325 IN ULONG Protection, 326 IN PPFN_NUMBER Pages, 327 IN ULONG PageCount, 328 IN BOOLEAN MarkAsMapped) 329 { 330 PMMPTE PointerPte = NULL; 331 MMPTE TempPte; 332 PVOID Addr; 333 ULONG OldPdeOffset, PdeOffset, i; 334 DPRINT("[KMAP]: %p %d\n", Address, PageCount); 335 //ASSERT(Address >= MmSystemRangeStart); 336 337 // 338 // Get our template PTE 339 // 340 TempPte = MiArmTemplatePte; 341 342 // 343 // Loop every page 344 // 345 Addr = Address; 346 OldPdeOffset = MiGetPdeOffset(Addr) + 1; 347 for (i = 0; i < PageCount; i++) 348 { 349 // 350 // Get the next PDE offset and check if it's a new one 351 // 352 PdeOffset = MiGetPdeOffset(Addr); 353 if (OldPdeOffset != PdeOffset) 354 { 355 // 356 // Get rid of the old L2 Table, if this was the last PTE on it 357 // 358 MiUnmapPageTable(PointerPte); 359 360 // 361 // Get the PTE for this address, and create the PDE for it 362 // 363 PointerPte = MiGetPageTableForProcess(NULL, Addr, TRUE); 364 ASSERT(PointerPte); 365 } 366 else 367 { 368 // 369 // Go to the next PTE on this PDE 370 // 371 ASSERT(PointerPte); 372 PointerPte++; 373 } 374 375 // 376 // Save the current PDE 377 // 378 OldPdeOffset = PdeOffset; 379 380 // 381 // Set the PFN 382 // 383 TempPte.u.Hard.PageFrameNumber = *Pages++; 384 385 // 386 // Write the PTE 387 // 388 ASSERT(PointerPte->u.Hard.Valid == 0); 389 ASSERT(TempPte.u.Hard.Valid == 1); 390 *PointerPte = TempPte; 391 392 // 393 // Move to the next page 394 // 395 Addr = (PVOID)((ULONG_PTR)Addr + PAGE_SIZE); 396 } 397 398 // 399 // All done 400 // 401 return STATUS_SUCCESS; 402 } 403 404 NTSTATUS 405 NTAPI 406 MmCreateVirtualMappingUnsafe(IN PEPROCESS Process, 407 IN PVOID Address, 408 IN ULONG Protection, 409 IN PPFN_NUMBER Pages, 410 IN ULONG PageCount) 411 { 412 // 413 // Are we only handling the kernel? 414 // 415 if (!(Process) || (Process == PsGetCurrentProcess())) 416 { 417 // 418 // Call the internal version 419 // 420 return MmCreateVirtualMappingInternal(Process, 421 Address, 422 Protection, 423 Pages, 424 PageCount, 425 TRUE); 426 } 427 428 // 429 // FIXME-USER: Support user-mode mappings 430 // 431 ASSERT(FALSE); 432 return 0; 433 } 434 435 NTSTATUS 436 NTAPI 437 MmCreateVirtualMapping(IN PEPROCESS Process, 438 IN PVOID Address, 439 IN ULONG Protection, 440 IN PPFN_NUMBER Pages, 441 IN ULONG PageCount) 442 { 443 ULONG i; 444 445 // 446 // Loop each page 447 // 448 for (i = 0; i < PageCount; i++) 449 { 450 // 451 // Make sure the page is marked as in use 452 // 453 ASSERT(MmIsPageInUse(Pages[i])); 454 } 455 456 // 457 // Call the unsafe version 458 // 459 return MmCreateVirtualMappingUnsafe(Process, 460 Address, 461 Protection, 462 Pages, 463 PageCount); 464 } 465 466 VOID 467 NTAPI 468 MmDeleteVirtualMapping(IN PEPROCESS Process, 469 IN PVOID Address, 470 OUT PBOOLEAN WasDirty, 471 OUT PPFN_NUMBER Page) 472 { 473 PMMPTE PointerPte; 474 MMPTE Pte; 475 PFN_NUMBER Pfn = 0; 476 477 // 478 // Get the PTE 479 // 480 PointerPte = MiGetPageTableForProcess(NULL, Address, FALSE); 481 if (PointerPte) 482 { 483 // 484 // Save and destroy the PTE 485 // 486 Pte = *PointerPte; 487 PointerPte->u.Hard.AsUlong = 0; 488 489 // 490 // Flush the TLB 491 // 492 MiFlushTlb(PointerPte, Address); 493 494 // 495 // Unmap the PFN 496 // 497 Pfn = Pte.u.Hard.PageFrameNumber; 498 499 // 500 // Release the PFN if it was ours 501 // 502 if ((FreePage) && (Pfn)) MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn); 503 } 504 505 // 506 // Return if the page was dirty 507 // 508 if (WasDirty) *WasDirty = FALSE; // LIE!!! 509 if (Page) *Page = Pfn; 510 } 511 512 VOID 513 NTAPI 514 MmDeletePageFileMapping(IN PEPROCESS Process, 515 IN PVOID Address, 516 IN SWAPENTRY *SwapEntry) 517 { 518 // 519 // TODO 520 // 521 UNIMPLEMENTED_DBGBREAK(); 522 } 523 524 NTSTATUS 525 NTAPI 526 MmCreatePageFileMapping(IN PEPROCESS Process, 527 IN PVOID Address, 528 IN SWAPENTRY SwapEntry) 529 { 530 // 531 // TODO 532 // 533 UNIMPLEMENTED_DBGBREAK(); 534 return STATUS_NOT_IMPLEMENTED; 535 } 536 537 PFN_NUMBER 538 NTAPI 539 MmGetPfnForProcess(IN PEPROCESS Process, 540 IN PVOID Address) 541 { 542 MMPTE Pte; 543 544 // 545 // Get the PTE 546 // 547 Pte = MiGetPageEntryForProcess(Process, Address); 548 if (Pte.u.Hard.Valid == 0) return 0; 549 550 // 551 // Return PFN 552 // 553 return Pte.u.Hard.PageFrameNumber; 554 } 555 556 BOOLEAN 557 NTAPI 558 MmIsDirtyPage(IN PEPROCESS Process, 559 IN PVOID Address) 560 { 561 // 562 // TODO 563 // 564 UNIMPLEMENTED_DBGBREAK(); 565 return FALSE; 566 } 567 568 VOID 569 NTAPI 570 MmSetCleanPage(IN PEPROCESS Process, 571 IN PVOID Address) 572 { 573 // 574 // TODO 575 // 576 UNIMPLEMENTED_DBGBREAK(); 577 } 578 579 VOID 580 NTAPI 581 MmSetDirtyPage(IN PEPROCESS Process, 582 IN PVOID Address) 583 { 584 // 585 // TODO 586 // 587 UNIMPLEMENTED_DBGBREAK(); 588 } 589 590 BOOLEAN 591 NTAPI 592 MmIsPagePresent(IN PEPROCESS Process, 593 IN PVOID Address) 594 { 595 // 596 // Fault PTEs are 0, which is FALSE (non-present) 597 // 598 return MiGetPageEntryForProcess(Process, Address).u.Hard.Valid; 599 } 600 601 BOOLEAN 602 NTAPI 603 MmIsPageSwapEntry(IN PEPROCESS Process, 604 IN PVOID Address) 605 { 606 MMPTE Pte; 607 608 // 609 // Get the PTE 610 // 611 Pte = MiGetPageEntryForProcess(Process, Address); 612 613 // 614 // Make sure it exists, but is faulting 615 // 616 return (Pte.u.Hard.Valid == 0) && (Pte.u.Hard.AsUlong); 617 } 618 619 ULONG 620 NTAPI 621 MmGetPageProtect(IN PEPROCESS Process, 622 IN PVOID Address) 623 { 624 // 625 // We don't enforce any protection on the pages -- they are all RWX 626 // 627 return PAGE_READWRITE; 628 } 629 630 VOID 631 NTAPI 632 MmSetPageProtect(IN PEPROCESS Process, 633 IN PVOID Address, 634 IN ULONG Protection) 635 { 636 // 637 // We don't enforce any protection on the pages -- they are all RWX 638 // 639 return; 640 } 641 642 VOID 643 NTAPI 644 MmInitGlobalKernelPageDirectory(VOID) 645 { 646 ULONG i; 647 PULONG CurrentPageDirectory = (PULONG)PDE_BASE; 648 649 // 650 // Good place to setup template PTE/PDEs. 651 // We are lazy and pick a known-good PTE 652 // 653 MiArmTemplatePte = *MiAddressToPte(0x80000000); 654 MiArmTemplatePde = *MiAddressToPde(0x80000000); 655 656 // 657 // Loop the 2GB of address space which belong to the kernel 658 // 659 for (i = MiGetPdeOffset(MmSystemRangeStart); i < 1024; i++) 660 { 661 // 662 // Check if we have an entry for this already 663 // 664 if ((i != MiGetPdeOffset(PTE_BASE)) && 665 (i != MiGetPdeOffset(HYPER_SPACE)) && 666 (!MmGlobalKernelPageDirectory[i]) && 667 (CurrentPageDirectory[i])) 668 { 669 // 670 // We don't, link it in our global page directory 671 // 672 MmGlobalKernelPageDirectory[i] = CurrentPageDirectory[i]; 673 } 674 } 675 } 676 677 678 /* PUBLIC FUNCTIONS ***********************************************************/ 679 680 /* 681 * @implemented 682 */ 683 PHYSICAL_ADDRESS 684 NTAPI 685 MmGetPhysicalAddress(IN PVOID Address) 686 { 687 PHYSICAL_ADDRESS PhysicalAddress; 688 MMPTE Pte; 689 690 // 691 // Early boot PCR check 692 // 693 if (Address == PCR) 694 { 695 // 696 // ARM Hack while we still use a section PTE 697 // 698 PMMPDE_HARDWARE PointerPde; 699 PointerPde = MiAddressToPde(PCR); 700 ASSERT(PointerPde->u.Hard.Section.Valid == 1); 701 PhysicalAddress.QuadPart = PointerPde->u.Hard.Section.PageFrameNumber; 702 PhysicalAddress.QuadPart <<= CPT_SHIFT; 703 PhysicalAddress.LowPart += BYTE_OFFSET(Address); 704 return PhysicalAddress; 705 } 706 707 // 708 // Get the PTE 709 // 710 Pte = MiGetPageEntryForProcess(NULL, Address); 711 if (Pte.u.Hard.Valid) 712 { 713 // 714 // Return the information 715 // 716 PhysicalAddress.QuadPart = Pte.u.Hard.PageFrameNumber; 717 PhysicalAddress.QuadPart <<= PAGE_SHIFT; 718 PhysicalAddress.LowPart += BYTE_OFFSET(Address); 719 } 720 else 721 { 722 // 723 // Invalid or unmapped 724 // 725 PhysicalAddress.QuadPart = 0; 726 } 727 728 // 729 // Return the physical address 730 // 731 return PhysicalAddress; 732 } 733