PageDirectory.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright notice, this
  9. * list of conditions and the following disclaimer.
  10. *
  11. * 2. Redistributions in binary form must reproduce the above copyright notice,
  12. * this list of conditions and the following disclaimer in the documentation
  13. * and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  19. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  21. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  22. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  23. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  24. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #include <Kernel/Process.h>
  27. #include <Kernel/Random.h>
  28. #include <Kernel/Thread.h>
  29. #include <Kernel/VM/MemoryManager.h>
  30. #include <Kernel/VM/PageDirectory.h>
  31. namespace Kernel {
  32. static const uintptr_t userspace_range_base = 0x00800000;
  33. static const uintptr_t userspace_range_ceiling = 0xbe000000;
  34. static const uintptr_t kernelspace_range_base = 0xc0800000;
  35. static HashMap<u32, PageDirectory*>& cr3_map()
  36. {
  37. ASSERT_INTERRUPTS_DISABLED();
  38. static HashMap<u32, PageDirectory*>* map;
  39. if (!map)
  40. map = new HashMap<u32, PageDirectory*>;
  41. return *map;
  42. }
  43. RefPtr<PageDirectory> PageDirectory::find_by_cr3(u32 cr3)
  44. {
  45. InterruptDisabler disabler;
  46. return cr3_map().get(cr3).value_or({});
  47. }
  48. extern "C" PageDirectoryEntry* boot_pdpt[4];
  49. extern "C" PageDirectoryEntry boot_pd0[1024];
  50. extern "C" PageDirectoryEntry boot_pd3[1024];
  51. PageDirectory::PageDirectory()
  52. {
  53. m_range_allocator.initialize_with_range(VirtualAddress(0xc0800000), 0x3f000000);
  54. // Adopt the page tables already set up by boot.S
  55. PhysicalAddress boot_pdpt_paddr(virtual_to_low_physical((uintptr_t)boot_pdpt));
  56. PhysicalAddress boot_pd0_paddr(virtual_to_low_physical((uintptr_t)boot_pd0));
  57. PhysicalAddress boot_pd3_paddr(virtual_to_low_physical((uintptr_t)boot_pd3));
  58. klog() << "MM: boot_pdpt @ " << boot_pdpt_paddr;
  59. klog() << "MM: boot_pd0 @ " << boot_pd0_paddr;
  60. klog() << "MM: boot_pd3 @ " << boot_pd3_paddr;
  61. m_directory_table = PhysicalPage::create(boot_pdpt_paddr, true, false);
  62. m_directory_pages[0] = PhysicalPage::create(boot_pd0_paddr, true, false);
  63. m_directory_pages[3] = PhysicalPage::create(boot_pd3_paddr, true, false);
  64. }
  65. PageDirectory::PageDirectory(Process& process, const RangeAllocator* parent_range_allocator)
  66. : m_process(&process)
  67. {
  68. if (parent_range_allocator) {
  69. m_range_allocator.initialize_from_parent(*parent_range_allocator);
  70. } else {
  71. size_t random_offset = (get_good_random<u32>() % 32 * MB) & PAGE_MASK;
  72. u32 base = userspace_range_base + random_offset;
  73. m_range_allocator.initialize_with_range(VirtualAddress(base), userspace_range_ceiling - base);
  74. }
  75. // Set up a userspace page directory
  76. m_directory_table = MM.allocate_user_physical_page();
  77. m_directory_pages[0] = MM.allocate_user_physical_page();
  78. m_directory_pages[1] = MM.allocate_user_physical_page();
  79. m_directory_pages[2] = MM.allocate_user_physical_page();
  80. // Share the top 1 GB of kernel-only mappings (>=3GB or >=0xc0000000)
  81. m_directory_pages[3] = MM.kernel_page_directory().m_directory_pages[3];
  82. {
  83. InterruptDisabler disabler;
  84. auto& table = *(PageDirectoryPointerTable*)MM.quickmap_page(*m_directory_table);
  85. table.raw[0] = (u64)m_directory_pages[0]->paddr().as_ptr() | 1;
  86. table.raw[1] = (u64)m_directory_pages[1]->paddr().as_ptr() | 1;
  87. table.raw[2] = (u64)m_directory_pages[2]->paddr().as_ptr() | 1;
  88. table.raw[3] = (u64)m_directory_pages[3]->paddr().as_ptr() | 1;
  89. MM.unquickmap_page();
  90. }
  91. // Clone bottom 2 MB of mappings from kernel_page_directory
  92. PageDirectoryEntry buffer;
  93. auto* kernel_pd = MM.quickmap_pd(MM.kernel_page_directory(), 0);
  94. memcpy(&buffer, kernel_pd, sizeof(PageDirectoryEntry));
  95. auto* new_pd = MM.quickmap_pd(*this, 0);
  96. memcpy(new_pd, &buffer, sizeof(PageDirectoryEntry));
  97. InterruptDisabler disabler;
  98. cr3_map().set(cr3(), this);
  99. }
  100. PageDirectory::~PageDirectory()
  101. {
  102. #ifdef MM_DEBUG
  103. dbg() << "MM: ~PageDirectory K" << this;
  104. #endif
  105. InterruptDisabler disabler;
  106. cr3_map().remove(cr3());
  107. }
  108. }