MemoryManager.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762
  1. #include "MemoryManager.h"
  2. #include <AK/Assertions.h>
  3. #include <AK/kstdio.h>
  4. #include <AK/kmalloc.h>
  5. #include "i386.h"
  6. #include "StdLib.h"
  7. #include "Process.h"
  8. #include <LibC/errno_numbers.h>
  9. //#define MM_DEBUG
  10. //#define PAGE_FAULT_DEBUG
  11. static MemoryManager* s_the;
  12. MemoryManager& MM
  13. {
  14. return *s_the;
  15. }
  16. MemoryManager::MemoryManager()
  17. {
  18. m_kernel_page_directory = make<PageDirectory>(PhysicalAddress(0x4000));
  19. m_page_table_zero = (dword*)0x6000;
  20. initialize_paging();
  21. }
  22. MemoryManager::~MemoryManager()
  23. {
  24. }
  25. PageDirectory::PageDirectory(PhysicalAddress paddr)
  26. {
  27. kprintf("Instantiating PageDirectory with specific paddr P%x\n", paddr.get());
  28. m_directory_page = adopt(*new PhysicalPage(paddr, true));
  29. }
  30. PageDirectory::PageDirectory()
  31. {
  32. MM.populate_page_directory(*this);
  33. }
  34. void MemoryManager::populate_page_directory(PageDirectory& page_directory)
  35. {
  36. page_directory.m_directory_page = allocate_supervisor_physical_page();
  37. memset(page_directory.entries(), 0, PAGE_SIZE);
  38. page_directory.entries()[0] = kernel_page_directory().entries()[0];
  39. }
  40. void MemoryManager::initialize_paging()
  41. {
  42. static_assert(sizeof(MemoryManager::PageDirectoryEntry) == 4);
  43. static_assert(sizeof(MemoryManager::PageTableEntry) == 4);
  44. memset(m_page_table_zero, 0, PAGE_SIZE);
  45. #ifdef MM_DEBUG
  46. dbgprintf("MM: Kernel page directory @ %p\n", kernel_page_directory().cr3());
  47. #endif
  48. #ifdef MM_DEBUG
  49. dbgprintf("MM: Protect against null dereferences\n");
  50. #endif
  51. // Make null dereferences crash.
  52. map_protected(LinearAddress(0), PAGE_SIZE);
  53. #ifdef MM_DEBUG
  54. dbgprintf("MM: Identity map bottom 4MB\n");
  55. #endif
  56. // The bottom 4 MB (except for the null page) are identity mapped & supervisor only.
  57. // Every process shares these mappings.
  58. create_identity_mapping(kernel_page_directory(), LinearAddress(PAGE_SIZE), (4 * MB) - PAGE_SIZE);
  59. // Physical pages from this range are used for page tables.
  60. for (size_t i = (1 * MB); i < (4 * MB); i += PAGE_SIZE)
  61. m_free_supervisor_physical_pages.append(adopt(*new PhysicalPage(PhysicalAddress(i), true)));
  62. #ifdef MM_DEBUG
  63. dbgprintf("MM: 4MB-8MB available for allocation\n");
  64. #endif
  65. // The physical pages 4 MB through 8 MB are available for allocation.
  66. for (size_t i = (4 * MB); i < (8 * MB); i += PAGE_SIZE)
  67. m_free_physical_pages.append(adopt(*new PhysicalPage(PhysicalAddress(i), false)));
  68. m_quickmap_addr = LinearAddress(m_free_physical_pages.takeLast().leakRef()->paddr().get());
  69. kprintf("MM: Quickmap will use P%x\n", m_quickmap_addr.get());
  70. #ifdef MM_DEBUG
  71. dbgprintf("MM: Installing page directory\n");
  72. #endif
  73. asm volatile("movl %%eax, %%cr3"::"a"(kernel_page_directory().cr3()));
  74. asm volatile(
  75. "movl %cr0, %eax\n"
  76. "orl $0x80000001, %eax\n"
  77. "movl %eax, %cr0\n"
  78. );
  79. }
  80. RetainPtr<PhysicalPage> MemoryManager::allocate_page_table(PageDirectory& page_directory, unsigned index)
  81. {
  82. ASSERT(!page_directory.m_physical_pages.contains(index));
  83. auto physical_page = allocate_supervisor_physical_page();
  84. if (!physical_page)
  85. return nullptr;
  86. dword address = physical_page->paddr().get();
  87. memset((void*)address, 0, PAGE_SIZE);
  88. page_directory.m_physical_pages.set(index, physical_page.copyRef());
  89. return physical_page;
  90. }
  91. void MemoryManager::remove_identity_mapping(PageDirectory& page_directory, LinearAddress laddr, size_t size)
  92. {
  93. InterruptDisabler disabler;
  94. // FIXME: ASSERT(laddr is 4KB aligned);
  95. for (dword offset = 0; offset < size; offset += PAGE_SIZE) {
  96. auto pte_address = laddr.offset(offset);
  97. auto pte = ensure_pte(page_directory, pte_address);
  98. pte.set_physical_page_base(0);
  99. pte.set_user_allowed(false);
  100. pte.set_present(true);
  101. pte.set_writable(true);
  102. flush_tlb(pte_address);
  103. }
  104. }
  105. auto MemoryManager::ensure_pte(PageDirectory& page_directory, LinearAddress laddr) -> PageTableEntry
  106. {
  107. ASSERT_INTERRUPTS_DISABLED();
  108. dword page_directory_index = (laddr.get() >> 22) & 0x3ff;
  109. dword page_table_index = (laddr.get() >> 12) & 0x3ff;
  110. PageDirectoryEntry pde = PageDirectoryEntry(&page_directory.entries()[page_directory_index]);
  111. if (!pde.is_present()) {
  112. #ifdef MM_DEBUG
  113. dbgprintf("MM: PDE %u not present (requested for L%x), allocating\n", page_directory_index, laddr.get());
  114. #endif
  115. if (page_directory_index == 0) {
  116. ASSERT(&page_directory == m_kernel_page_directory.ptr());
  117. pde.setPageTableBase((dword)m_page_table_zero);
  118. pde.set_user_allowed(false);
  119. pde.set_present(true);
  120. pde.set_writable(true);
  121. } else {
  122. ASSERT(&page_directory != m_kernel_page_directory.ptr());
  123. auto page_table = allocate_page_table(page_directory, page_directory_index);
  124. #ifdef MM_DEBUG
  125. dbgprintf("MM: PD K%x (%s) at P%x allocated page table #%u (for L%x) at P%x\n",
  126. &page_directory,
  127. &page_directory == m_kernel_page_directory.ptr() ? "Kernel" : "User",
  128. page_directory.cr3(),
  129. page_directory_index,
  130. laddr.get(),
  131. page_table->paddr().get());
  132. #endif
  133. pde.setPageTableBase(page_table->paddr().get());
  134. pde.set_user_allowed(true);
  135. pde.set_present(true);
  136. pde.set_writable(true);
  137. page_directory.m_physical_pages.set(page_directory_index, move(page_table));
  138. }
  139. }
  140. return PageTableEntry(&pde.pageTableBase()[page_table_index]);
  141. }
  142. void MemoryManager::map_protected(LinearAddress linearAddress, size_t length)
  143. {
  144. InterruptDisabler disabler;
  145. // FIXME: ASSERT(linearAddress is 4KB aligned);
  146. for (dword offset = 0; offset < length; offset += PAGE_SIZE) {
  147. auto pteAddress = linearAddress.offset(offset);
  148. auto pte = ensure_pte(kernel_page_directory(), pteAddress);
  149. pte.set_physical_page_base(pteAddress.get());
  150. pte.set_user_allowed(false);
  151. pte.set_present(false);
  152. pte.set_writable(false);
  153. flush_tlb(pteAddress);
  154. }
  155. }
  156. void MemoryManager::create_identity_mapping(PageDirectory& page_directory, LinearAddress laddr, size_t size)
  157. {
  158. InterruptDisabler disabler;
  159. ASSERT((laddr.get() & ~PAGE_MASK) == 0);
  160. for (dword offset = 0; offset < size; offset += PAGE_SIZE) {
  161. auto pteAddress = laddr.offset(offset);
  162. auto pte = ensure_pte(page_directory, pteAddress);
  163. pte.set_physical_page_base(pteAddress.get());
  164. pte.set_user_allowed(false);
  165. pte.set_present(true);
  166. pte.set_writable(true);
  167. page_directory.flush(pteAddress);
  168. }
  169. }
  170. void MemoryManager::initialize()
  171. {
  172. s_the = new MemoryManager;
  173. }
  174. Region* MemoryManager::region_from_laddr(Process& process, LinearAddress laddr)
  175. {
  176. ASSERT_INTERRUPTS_DISABLED();
  177. // FIXME: Use a binary search tree (maybe red/black?) or some other more appropriate data structure!
  178. for (auto& region : process.m_regions) {
  179. if (region->contains(laddr))
  180. return region.ptr();
  181. }
  182. kprintf("%s(%u) Couldn't find region for L%x (CR3=%x)\n", process.name().characters(), process.pid(), laddr.get());
  183. return nullptr;
  184. }
  185. bool MemoryManager::zero_page(PageDirectory& page_directory, Region& region, unsigned page_index_in_region)
  186. {
  187. ASSERT_INTERRUPTS_DISABLED();
  188. auto& vmo = region.vmo();
  189. auto physical_page = allocate_physical_page();
  190. byte* dest_ptr = quickmap_page(*physical_page);
  191. memset(dest_ptr, 0, PAGE_SIZE);
  192. #ifdef PAGE_FAULT_DEBUG
  193. dbgprintf(" >> ZERO P%x\n", physical_page->paddr().get());
  194. #endif
  195. unquickmap_page();
  196. region.cow_map.set(page_index_in_region, false);
  197. vmo.physical_pages()[page_index_in_region] = move(physical_page);
  198. remap_region_page(page_directory, region, page_index_in_region, true);
  199. return true;
  200. }
  201. bool MemoryManager::copy_on_write(Process& process, Region& region, unsigned page_index_in_region)
  202. {
  203. ASSERT_INTERRUPTS_DISABLED();
  204. auto& vmo = region.vmo();
  205. if (vmo.physical_pages()[page_index_in_region]->retain_count() == 1) {
  206. #ifdef PAGE_FAULT_DEBUG
  207. dbgprintf(" >> It's a COW page but nobody is sharing it anymore. Remap r/w\n");
  208. #endif
  209. region.cow_map.set(page_index_in_region, false);
  210. remap_region_page(process.page_directory(), region, page_index_in_region, true);
  211. return true;
  212. }
  213. #ifdef PAGE_FAULT_DEBUG
  214. dbgprintf(" >> It's a COW page and it's time to COW!\n");
  215. #endif
  216. auto physical_page_to_copy = move(vmo.physical_pages()[page_index_in_region]);
  217. auto physical_page = allocate_physical_page();
  218. byte* dest_ptr = quickmap_page(*physical_page);
  219. const byte* src_ptr = region.linearAddress.offset(page_index_in_region * PAGE_SIZE).asPtr();
  220. #ifdef PAGE_FAULT_DEBUG
  221. dbgprintf(" >> COW P%x <- P%x\n", physical_page->paddr().get(), physical_page_to_copy->paddr().get());
  222. #endif
  223. memcpy(dest_ptr, src_ptr, PAGE_SIZE);
  224. vmo.physical_pages()[page_index_in_region] = move(physical_page);
  225. unquickmap_page();
  226. region.cow_map.set(page_index_in_region, false);
  227. remap_region_page(process.page_directory(), region, page_index_in_region, true);
  228. return true;
  229. }
  230. bool Region::page_in(PageDirectory& page_directory)
  231. {
  232. ASSERT(!vmo().is_anonymous());
  233. ASSERT(vmo().vnode());
  234. #ifdef MM_DEBUG
  235. dbgprintf("MM: page_in %u pages\n", page_count());
  236. #endif
  237. for (size_t i = 0; i < page_count(); ++i) {
  238. auto& vmo_page = vmo().physical_pages()[first_page_index() + i];
  239. if (vmo_page.is_null()) {
  240. bool success = MM.page_in_from_vnode(page_directory, *this, i);
  241. if (!success)
  242. return false;
  243. }
  244. MM.remap_region_page(page_directory, *this, i, true);
  245. }
  246. return true;
  247. }
  248. bool MemoryManager::page_in_from_vnode(PageDirectory& page_directory, Region& region, unsigned page_index_in_region)
  249. {
  250. auto& vmo = region.vmo();
  251. ASSERT(!vmo.is_anonymous());
  252. ASSERT(vmo.vnode());
  253. auto& vnode = *vmo.vnode();
  254. auto& vmo_page = vmo.physical_pages()[region.first_page_index() + page_index_in_region];
  255. ASSERT(vmo_page.is_null());
  256. vmo_page = allocate_physical_page();
  257. if (vmo_page.is_null()) {
  258. kprintf("MM: page_in_from_vnode was unable to allocate a physical page\n");
  259. return false;
  260. }
  261. remap_region_page(page_directory, region, page_index_in_region, true);
  262. byte* dest_ptr = region.linearAddress.offset(page_index_in_region * PAGE_SIZE).asPtr();
  263. #ifdef MM_DEBUG
  264. dbgprintf("MM: page_in_from_vnode ready to read from vnode, will write to L%x!\n", dest_ptr);
  265. #endif
  266. sti(); // Oh god here we go...
  267. ASSERT(vnode.core_inode());
  268. auto nread = vnode.core_inode()->read_bytes(vmo.vnode_offset() + ((region.first_page_index() + page_index_in_region) * PAGE_SIZE), PAGE_SIZE, dest_ptr, nullptr);
  269. if (nread < 0) {
  270. kprintf("MM: page_in_from_vnode had error (%d) while reading!\n", nread);
  271. return false;
  272. }
  273. if (nread < PAGE_SIZE) {
  274. // If we read less than a page, zero out the rest to avoid leaking uninitialized data.
  275. memset(dest_ptr + nread, 0, PAGE_SIZE - nread);
  276. }
  277. cli();
  278. return true;
  279. }
  280. PageFaultResponse MemoryManager::handle_page_fault(const PageFault& fault)
  281. {
  282. ASSERT_INTERRUPTS_DISABLED();
  283. #ifdef PAGE_FAULT_DEBUG
  284. dbgprintf("MM: handle_page_fault(%w) at L%x\n", fault.code(), fault.laddr().get());
  285. #endif
  286. ASSERT(fault.laddr() != m_quickmap_addr);
  287. auto* region = region_from_laddr(*current, fault.laddr());
  288. if (!region) {
  289. kprintf("NP(error) fault at invalid address L%x\n", fault.laddr().get());
  290. return PageFaultResponse::ShouldCrash;
  291. }
  292. auto page_index_in_region = region->page_index_from_address(fault.laddr());
  293. if (fault.is_not_present()) {
  294. if (region->vmo().vnode()) {
  295. dbgprintf("NP(vnode) fault in Region{%p}[%u]\n", region, page_index_in_region);
  296. page_in_from_vnode(*current->m_page_directory, *region, page_index_in_region);
  297. return PageFaultResponse::Continue;
  298. } else {
  299. dbgprintf("NP(zero) fault in Region{%p}[%u]\n", region, page_index_in_region);
  300. zero_page(*current->m_page_directory, *region, page_index_in_region);
  301. return PageFaultResponse::Continue;
  302. }
  303. } else if (fault.is_protection_violation()) {
  304. if (region->cow_map.get(page_index_in_region)) {
  305. dbgprintf("PV(cow) fault in Region{%p}[%u]\n", region, page_index_in_region);
  306. bool success = copy_on_write(*current, *region, page_index_in_region);
  307. ASSERT(success);
  308. return PageFaultResponse::Continue;
  309. }
  310. kprintf("PV(error) fault in Region{%p}[%u]\n", region, page_index_in_region);
  311. } else {
  312. ASSERT_NOT_REACHED();
  313. }
  314. return PageFaultResponse::ShouldCrash;
  315. }
  316. RetainPtr<PhysicalPage> MemoryManager::allocate_physical_page()
  317. {
  318. InterruptDisabler disabler;
  319. if (1 > m_free_physical_pages.size())
  320. return { };
  321. #ifdef MM_DEBUG
  322. dbgprintf("MM: allocate_physical_page vending P%x (%u remaining)\n", m_free_physical_pages.last()->paddr().get(), m_free_physical_pages.size());
  323. #endif
  324. return m_free_physical_pages.takeLast();
  325. }
  326. RetainPtr<PhysicalPage> MemoryManager::allocate_supervisor_physical_page()
  327. {
  328. InterruptDisabler disabler;
  329. if (1 > m_free_supervisor_physical_pages.size())
  330. return { };
  331. #ifdef MM_DEBUG
  332. dbgprintf("MM: allocate_supervisor_physical_page vending P%x (%u remaining)\n", m_free_supervisor_physical_pages.last()->paddr().get(), m_free_supervisor_physical_pages.size());
  333. #endif
  334. return m_free_supervisor_physical_pages.takeLast();
  335. }
  336. void MemoryManager::enter_process_paging_scope(Process& process)
  337. {
  338. InterruptDisabler disabler;
  339. current->m_tss.cr3 = process.page_directory().cr3();
  340. asm volatile("movl %%eax, %%cr3"::"a"(process.page_directory().cr3()):"memory");
  341. }
  342. void MemoryManager::flush_entire_tlb()
  343. {
  344. asm volatile(
  345. "mov %cr3, %eax\n"
  346. "mov %eax, %cr3\n"
  347. );
  348. }
  349. void MemoryManager::flush_tlb(LinearAddress laddr)
  350. {
  351. asm volatile("invlpg %0": :"m" (*(char*)laddr.get()) : "memory");
  352. }
  353. byte* MemoryManager::quickmap_page(PhysicalPage& physical_page)
  354. {
  355. ASSERT_INTERRUPTS_DISABLED();
  356. auto page_laddr = m_quickmap_addr;
  357. auto pte = ensure_pte(current->page_directory(), page_laddr);
  358. pte.set_physical_page_base(physical_page.paddr().get());
  359. pte.set_present(true);
  360. pte.set_writable(true);
  361. flush_tlb(page_laddr);
  362. ASSERT((dword)pte.physical_page_base() == physical_page.paddr().get());
  363. #ifdef MM_DEBUG
  364. dbgprintf("MM: >> quickmap_page L%x => P%x @ PTE=%p\n", page_laddr, physical_page.paddr().get(), pte.ptr());
  365. #endif
  366. return page_laddr.asPtr();
  367. }
  368. void MemoryManager::unquickmap_page()
  369. {
  370. ASSERT_INTERRUPTS_DISABLED();
  371. auto page_laddr = m_quickmap_addr;
  372. auto pte = ensure_pte(current->page_directory(), page_laddr);
  373. #ifdef MM_DEBUG
  374. auto old_physical_address = pte.physical_page_base();
  375. #endif
  376. pte.set_physical_page_base(0);
  377. pte.set_present(false);
  378. pte.set_writable(false);
  379. flush_tlb(page_laddr);
  380. #ifdef MM_DEBUG
  381. dbgprintf("MM: >> unquickmap_page L%x =/> P%x\n", page_laddr, old_physical_address);
  382. #endif
  383. }
  384. void MemoryManager::remap_region_page(PageDirectory& page_directory, Region& region, unsigned page_index_in_region, bool user_allowed)
  385. {
  386. InterruptDisabler disabler;
  387. auto page_laddr = region.linearAddress.offset(page_index_in_region * PAGE_SIZE);
  388. auto pte = ensure_pte(page_directory, page_laddr);
  389. auto& physical_page = region.vmo().physical_pages()[page_index_in_region];
  390. ASSERT(physical_page);
  391. pte.set_physical_page_base(physical_page->paddr().get());
  392. pte.set_present(true); // FIXME: Maybe we should use the is_readable flag here?
  393. if (region.cow_map.get(page_index_in_region))
  394. pte.set_writable(false);
  395. else
  396. pte.set_writable(region.is_writable);
  397. pte.set_user_allowed(user_allowed);
  398. page_directory.flush(page_laddr);
  399. #ifdef MM_DEBUG
  400. dbgprintf("MM: >> remap_region_page (PD=%x, PTE=P%x) '%s' L%x => P%x (@%p)\n", &page_directory, pte.ptr(), region.name.characters(), page_laddr.get(), physical_page->paddr().get(), physical_page.ptr());
  401. #endif
  402. }
  403. void MemoryManager::remap_region(Process& process, Region& region)
  404. {
  405. InterruptDisabler disabler;
  406. map_region_at_address(process.page_directory(), region, region.linearAddress, true);
  407. }
  408. void MemoryManager::map_region_at_address(PageDirectory& page_directory, Region& region, LinearAddress laddr, bool user_allowed)
  409. {
  410. InterruptDisabler disabler;
  411. auto& vmo = region.vmo();
  412. #ifdef MM_DEBUG
  413. dbgprintf("MM: map_region_at_address will map VMO pages %u - %u (VMO page count: %u)\n", region.first_page_index(), region.last_page_index(), vmo.page_count());
  414. #endif
  415. for (size_t i = 0; i < region.page_count(); ++i) {
  416. auto page_laddr = laddr.offset(i * PAGE_SIZE);
  417. auto pte = ensure_pte(page_directory, page_laddr);
  418. auto& physical_page = vmo.physical_pages()[region.first_page_index() + i];
  419. if (physical_page) {
  420. pte.set_physical_page_base(physical_page->paddr().get());
  421. pte.set_present(true); // FIXME: Maybe we should use the is_readable flag here?
  422. // FIXME: It seems wrong that the *region* cow map is essentially using *VMO* relative indices.
  423. if (region.cow_map.get(region.first_page_index() + i))
  424. pte.set_writable(false);
  425. else
  426. pte.set_writable(region.is_writable);
  427. } else {
  428. pte.set_physical_page_base(0);
  429. pte.set_present(false);
  430. pte.set_writable(region.is_writable);
  431. }
  432. pte.set_user_allowed(user_allowed);
  433. page_directory.flush(page_laddr);
  434. #ifdef MM_DEBUG
  435. dbgprintf("MM: >> map_region_at_address (PD=%x) '%s' L%x => P%x (@%p)\n", &page_directory, region.name.characters(), page_laddr, physical_page ? physical_page->paddr().get() : 0, physical_page.ptr());
  436. #endif
  437. }
  438. }
  439. void MemoryManager::unmap_range(PageDirectory& page_directory, LinearAddress laddr, size_t size)
  440. {
  441. ASSERT((size % PAGE_SIZE) == 0);
  442. InterruptDisabler disabler;
  443. size_t numPages = size / PAGE_SIZE;
  444. for (size_t i = 0; i < numPages; ++i) {
  445. auto page_laddr = laddr.offset(i * PAGE_SIZE);
  446. auto pte = ensure_pte(page_directory, page_laddr);
  447. pte.set_physical_page_base(0);
  448. pte.set_present(false);
  449. pte.set_writable(false);
  450. pte.set_user_allowed(false);
  451. page_directory.flush(page_laddr);
  452. #ifdef MM_DEBUG
  453. dbgprintf("MM: << unmap_range L%x =/> 0\n", page_laddr);
  454. #endif
  455. }
  456. }
  457. bool MemoryManager::unmap_region(Process& process, Region& region)
  458. {
  459. InterruptDisabler disabler;
  460. for (size_t i = 0; i < region.page_count(); ++i) {
  461. auto laddr = region.linearAddress.offset(i * PAGE_SIZE);
  462. auto pte = ensure_pte(process.page_directory(), laddr);
  463. pte.set_physical_page_base(0);
  464. pte.set_present(false);
  465. pte.set_writable(false);
  466. pte.set_user_allowed(false);
  467. process.page_directory().flush(laddr);
  468. #ifdef MM_DEBUG
  469. auto& physical_page = region.vmo().physical_pages()[region.first_page_index() + i];
  470. dbgprintf("MM: >> Unmapped L%x => P%x <<\n", laddr, physical_page ? physical_page->paddr().get() : 0);
  471. #endif
  472. }
  473. return true;
  474. }
  475. bool MemoryManager::map_region(Process& process, Region& region)
  476. {
  477. map_region_at_address(process.page_directory(), region, region.linearAddress, true);
  478. return true;
  479. }
  480. bool MemoryManager::validate_user_read(const Process& process, LinearAddress laddr) const
  481. {
  482. dword pageDirectoryIndex = (laddr.get() >> 22) & 0x3ff;
  483. dword pageTableIndex = (laddr.get() >> 12) & 0x3ff;
  484. auto pde = PageDirectoryEntry(&const_cast<Process&>(process).page_directory().entries()[pageDirectoryIndex]);
  485. if (!pde.is_present())
  486. return false;
  487. auto pte = PageTableEntry(&pde.pageTableBase()[pageTableIndex]);
  488. if (!pte.is_present())
  489. return false;
  490. if (!pte.is_user_allowed())
  491. return false;
  492. return true;
  493. }
  494. bool MemoryManager::validate_user_write(const Process& process, LinearAddress laddr) const
  495. {
  496. dword pageDirectoryIndex = (laddr.get() >> 22) & 0x3ff;
  497. dword pageTableIndex = (laddr.get() >> 12) & 0x3ff;
  498. auto pde = PageDirectoryEntry(&const_cast<Process&>(process).page_directory().entries()[pageDirectoryIndex]);
  499. if (!pde.is_present())
  500. return false;
  501. auto pte = PageTableEntry(&pde.pageTableBase()[pageTableIndex]);
  502. if (!pte.is_present())
  503. return false;
  504. if (!pte.is_user_allowed())
  505. return false;
  506. if (!pte.is_writable())
  507. return false;
  508. return true;
  509. }
  510. RetainPtr<Region> Region::clone()
  511. {
  512. InterruptDisabler disabler;
  513. if (is_readable && !is_writable) {
  514. // Create a new region backed by the same VMObject.
  515. return adopt(*new Region(linearAddress, size, m_vmo.copyRef(), m_offset_in_vmo, String(name), is_readable, is_writable));
  516. }
  517. // Set up a COW region. The parent (this) region becomes COW as well!
  518. for (size_t i = 0; i < page_count(); ++i)
  519. cow_map.set(i, true);
  520. MM.remap_region(*current, *this);
  521. return adopt(*new Region(linearAddress, size, m_vmo->clone(), m_offset_in_vmo, String(name), is_readable, is_writable, true));
  522. }
  523. Region::Region(LinearAddress a, size_t s, String&& n, bool r, bool w, bool cow)
  524. : linearAddress(a)
  525. , size(s)
  526. , m_vmo(VMObject::create_anonymous(s))
  527. , name(move(n))
  528. , is_readable(r)
  529. , is_writable(w)
  530. , cow_map(Bitmap::create(m_vmo->page_count(), cow))
  531. {
  532. m_vmo->set_name(name);
  533. MM.register_region(*this);
  534. }
  535. Region::Region(LinearAddress a, size_t s, RetainPtr<Vnode>&& vnode, String&& n, bool r, bool w)
  536. : linearAddress(a)
  537. , size(s)
  538. , m_vmo(VMObject::create_file_backed(move(vnode), s))
  539. , name(move(n))
  540. , is_readable(r)
  541. , is_writable(w)
  542. , cow_map(Bitmap::create(m_vmo->page_count()))
  543. {
  544. MM.register_region(*this);
  545. }
  546. Region::Region(LinearAddress a, size_t s, RetainPtr<VMObject>&& vmo, size_t offset_in_vmo, String&& n, bool r, bool w, bool cow)
  547. : linearAddress(a)
  548. , size(s)
  549. , m_offset_in_vmo(offset_in_vmo)
  550. , m_vmo(move(vmo))
  551. , name(move(n))
  552. , is_readable(r)
  553. , is_writable(w)
  554. , cow_map(Bitmap::create(m_vmo->page_count(), cow))
  555. {
  556. MM.register_region(*this);
  557. }
  558. Region::~Region()
  559. {
  560. MM.unregister_region(*this);
  561. }
  562. PhysicalPage::PhysicalPage(PhysicalAddress paddr, bool supervisor)
  563. : m_supervisor(supervisor)
  564. , m_paddr(paddr)
  565. {
  566. }
  567. void PhysicalPage::return_to_freelist()
  568. {
  569. ASSERT((paddr().get() & ~PAGE_MASK) == 0);
  570. InterruptDisabler disabler;
  571. m_retain_count = 1;
  572. if (m_supervisor)
  573. MM.m_free_supervisor_physical_pages.append(adopt(*this));
  574. else
  575. MM.m_free_physical_pages.append(adopt(*this));
  576. #ifdef MM_DEBUG
  577. dbgprintf("MM: P%x released to freelist\n", m_paddr.get());
  578. #endif
  579. }
  580. RetainPtr<VMObject> VMObject::create_file_backed(RetainPtr<Vnode>&& vnode, size_t size)
  581. {
  582. InterruptDisabler disabler;
  583. if (vnode->vmo())
  584. return static_cast<VMObject*>(vnode->vmo());
  585. size = ceilDiv(size, PAGE_SIZE) * PAGE_SIZE;
  586. auto vmo = adopt(*new VMObject(move(vnode), size));
  587. vmo->vnode()->set_vmo(vmo.ptr());
  588. return vmo;
  589. }
  590. RetainPtr<VMObject> VMObject::create_anonymous(size_t size)
  591. {
  592. size = ceilDiv(size, PAGE_SIZE) * PAGE_SIZE;
  593. return adopt(*new VMObject(size));
  594. }
  595. RetainPtr<VMObject> VMObject::clone()
  596. {
  597. return adopt(*new VMObject(*this));
  598. }
  599. VMObject::VMObject(VMObject& other)
  600. : m_name(other.m_name)
  601. , m_anonymous(other.m_anonymous)
  602. , m_vnode_offset(other.m_vnode_offset)
  603. , m_size(other.m_size)
  604. , m_vnode(other.m_vnode)
  605. , m_physical_pages(other.m_physical_pages)
  606. {
  607. MM.register_vmo(*this);
  608. }
  609. VMObject::VMObject(size_t size)
  610. : m_anonymous(true)
  611. , m_size(size)
  612. {
  613. MM.register_vmo(*this);
  614. m_physical_pages.resize(page_count());
  615. }
  616. VMObject::VMObject(RetainPtr<Vnode>&& vnode, size_t size)
  617. : m_size(size)
  618. , m_vnode(move(vnode))
  619. {
  620. m_physical_pages.resize(page_count());
  621. MM.register_vmo(*this);
  622. }
  623. VMObject::~VMObject()
  624. {
  625. if (m_vnode) {
  626. ASSERT(m_vnode->vmo() == this);
  627. m_vnode->set_vmo(nullptr);
  628. }
  629. MM.unregister_vmo(*this);
  630. }
  631. int Region::commit(Process& process)
  632. {
  633. InterruptDisabler disabler;
  634. #ifdef MM_DEBUG
  635. dbgprintf("MM: commit %u pages in Region %p (VMO=%p) at L%x\n", vmo().page_count(), this, &vmo(), linearAddress.get());
  636. #endif
  637. for (size_t i = first_page_index(); i <= last_page_index(); ++i) {
  638. if (!vmo().physical_pages()[i].is_null())
  639. continue;
  640. auto physical_page = MM.allocate_physical_page();
  641. if (!physical_page) {
  642. kprintf("MM: commit was unable to allocate a physical page\n");
  643. return -ENOMEM;
  644. }
  645. vmo().physical_pages()[i] = move(physical_page);
  646. MM.remap_region_page(process.page_directory(), *this, i, true);
  647. }
  648. return 0;
  649. }
  650. void MemoryManager::register_vmo(VMObject& vmo)
  651. {
  652. InterruptDisabler disabler;
  653. m_vmos.set(&vmo);
  654. }
  655. void MemoryManager::unregister_vmo(VMObject& vmo)
  656. {
  657. InterruptDisabler disabler;
  658. m_vmos.remove(&vmo);
  659. }
  660. void MemoryManager::register_region(Region& region)
  661. {
  662. InterruptDisabler disabler;
  663. m_regions.set(&region);
  664. }
  665. void MemoryManager::unregister_region(Region& region)
  666. {
  667. InterruptDisabler disabler;
  668. m_regions.remove(&region);
  669. }
  670. size_t Region::committed() const
  671. {
  672. size_t bytes = 0;
  673. for (size_t i = 0; i < page_count(); ++i) {
  674. if (m_vmo->physical_pages()[first_page_index() + i])
  675. bytes += PAGE_SIZE;
  676. }
  677. return bytes;
  678. }
  679. PageDirectory::~PageDirectory()
  680. {
  681. ASSERT_INTERRUPTS_DISABLED();
  682. #ifdef MM_DEBUG
  683. dbgprintf("MM: ~PageDirectory K%x\n", this);
  684. #endif
  685. }
  686. void PageDirectory::flush(LinearAddress laddr)
  687. {
  688. if (&current->page_directory() == this)
  689. MM.flush_tlb(laddr);
  690. }