diff --git a/kernel/include/memory/AddressSpace.h b/kernel/include/memory/AddressSpace.h index ef40b774..151e35bd 100644 --- a/kernel/include/memory/AddressSpace.h +++ b/kernel/include/memory/AddressSpace.h @@ -7,8 +7,6 @@ struct AddressSpace void destroy(); - void detach(); - AddressSpace clone(); PageTable* get_pml4() @@ -16,13 +14,6 @@ struct AddressSpace return m_pml4; } - bool is_cloned() - { - return *m_refs > 1; - } - private: PageTable* m_pml4; - - int* m_refs; }; \ No newline at end of file diff --git a/kernel/src/memory/AddressSpace.cpp b/kernel/src/memory/AddressSpace.cpp index bef29b71..f444a5ef 100644 --- a/kernel/src/memory/AddressSpace.cpp +++ b/kernel/src/memory/AddressSpace.cpp @@ -4,27 +4,21 @@ #include "log/Log.h" #include "memory/PMM.h" #include "memory/VMM.h" +#include "misc/hang.h" #include "std/stdlib.h" +#include "std/string.h" #include "utils/move.h" AddressSpace AddressSpace::create() { AddressSpace result; result.m_pml4 = (PageTable*)PMM::request_page(); - result.m_refs = (int*)kmalloc(sizeof(int)); - *result.m_refs = 1; VMM::install_kernel_page_directory_into_address_space(result); return move(result); } void AddressSpace::destroy() { - if (is_cloned()) - { - kdbgln("Will not destroy a cloned address space, I don't own it"); - (*m_refs)--; - return; - } uint64_t pages_freed = 0; for (int i = 0; i < 512; i++) { @@ -78,26 +72,76 @@ void AddressSpace::destroy() pages_freed++; PMM::free_page(m_pml4); - kfree(m_refs); - kdbgln("Reclaimed %ld pages from address space!", pages_freed); } -void AddressSpace::detach() -{ - if (!is_cloned()) return; - (*m_refs)--; - m_refs = (int*)kmalloc(sizeof(int)); - *m_refs = 1; - m_pml4 = (PageTable*)PMM::request_page(); - VMM::install_kernel_page_directory_into_address_space(*this); -} - -AddressSpace AddressSpace::clone() +AddressSpace AddressSpace::clone() // FIXME: Add out-of-memory checks to this function. { AddressSpace result; - result.m_pml4 = m_pml4; - result.m_refs = m_refs; - *m_refs = *m_refs + 1; + result.m_pml4 = (PageTable*)PMM::request_page(); + if (!result.m_pml4) return result; + memcpy(result.m_pml4, m_pml4, PAGE_SIZE); + for (int i = 0; i < 512; i++) + { + PageDirectoryEntry& pdp_pde = m_pml4->entries[i]; + PageDirectoryEntry& cloned_pdp_pde = result.m_pml4->entries[i]; + if (!pdp_pde.present) continue; + if (pdp_pde.larger_pages) + { + void* cloned = PMM::request_page(); + memcpy(cloned, (void*)pdp_pde.get_address(), PAGE_SIZE); + cloned_pdp_pde.set_address((uint64_t)cloned); + continue; + } + PageTable* pdp = (PageTable*)pdp_pde.get_address(); + PageTable* cloned_pdp = (PageTable*)PMM::request_page(); + memcpy(cloned_pdp, pdp, PAGE_SIZE); + cloned_pdp_pde.set_address((uint64_t)cloned_pdp); + for (int j = 0; j < 511; j++) // skip the last page directory, it's the kernel one + { + PageDirectoryEntry& pd_pde = pdp->entries[j]; + PageDirectoryEntry& cloned_pd_pde = cloned_pdp->entries[j]; + if (!pd_pde.present) continue; + if (pd_pde.larger_pages) + { + void* cloned = PMM::request_page(); + memcpy(cloned, (void*)pd_pde.get_address(), PAGE_SIZE); + cloned_pd_pde.set_address((uint64_t)cloned); + continue; + } + PageTable* pd = (PageTable*)pd_pde.get_address(); + PageTable* cloned_pd = (PageTable*)PMM::request_page(); + memcpy(cloned_pd, pd, PAGE_SIZE); + cloned_pd_pde.set_address((uint64_t)cloned_pd); + for (int k = 0; k < 512; k++) + { + PageDirectoryEntry& pt_pde = pd->entries[k]; + PageDirectoryEntry& cloned_pt_pde = cloned_pd->entries[k]; + if (!pt_pde.present) continue; + if (pt_pde.larger_pages) + { + void* cloned = PMM::request_page(); + memcpy(cloned, (void*)pt_pde.get_address(), PAGE_SIZE); + cloned_pt_pde.set_address((uint64_t)cloned); + continue; + } + PageTable* pt = (PageTable*)pt_pde.get_address(); + PageTable* cloned_pt = (PageTable*)PMM::request_page(); + memcpy(cloned_pt, pt, PAGE_SIZE); + cloned_pt_pde.set_address((uint64_t)cloned_pt); + for (int l = 0; l < 512; l++) + { + PageDirectoryEntry& pde = pt->entries[l]; + PageDirectoryEntry& cloned_pde = cloned_pt->entries[l]; + if (!pde.present) continue; + void* cloned = PMM::request_page(); + memcpy(cloned, (void*)pde.get_address(), PAGE_SIZE); + cloned_pde.set_address((uint64_t)cloned); + continue; + } + } + } + } + VMM::install_kernel_page_directory_into_address_space(result); return result; } \ No newline at end of file