diff --git a/kernel/arch/i686/PageTable.cpp b/kernel/arch/i686/PageTable.cpp index b963fb02..9d5db99f 100644 --- a/kernel/arch/i686/PageTable.cpp +++ b/kernel/arch/i686/PageTable.cpp @@ -470,6 +470,48 @@ namespace Kernel invalidate_range(vaddr, page_count, true); } + void PageTable::remove_writable_from_range(vaddr_t vaddr, size_t size) + { + ASSERT(vaddr); + ASSERT(vaddr % PAGE_SIZE == 0); + + uint32_t pdpte = (vaddr >> 30) & 0x1FF; + uint32_t pde = (vaddr >> 21) & 0x1FF; + uint32_t pte = (vaddr >> 12) & 0x1FF; + + const uint32_t e_pdpte = ((vaddr + size - 1) >> 30) & 0x1FF; + const uint32_t e_pde = ((vaddr + size - 1) >> 21) & 0x1FF; + const uint32_t e_pte = ((vaddr + size - 1) >> 12) & 0x1FF; + + SpinLockGuard _(m_lock); + + const uint64_t* pdpt = P2V(m_highest_paging_struct); + for (; pdpte <= e_pdpte; pdpte++) + { + if (!(pdpt[pdpte] & Flags::Present)) + continue; + const uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask); + for (; pde < 512; pde++) + { + if (pdpte == e_pdpte && pde > e_pde) + break; + if (!(pd[pde] & Flags::ReadWrite)) + continue; + uint64_t* pt = P2V(pd[pde] & s_page_addr_mask); + for (; pte < 512; pte++) + { + if (pdpte == e_pdpte && pde == e_pde && pte > e_pte) + break; + pt[pte] &= ~static_cast(Flags::ReadWrite); + } + pte = 0; + } + pde = 0; + } + + invalidate_range(vaddr, size / PAGE_SIZE, true); + } + uint64_t PageTable::get_page_data(vaddr_t vaddr) const { ASSERT(vaddr % PAGE_SIZE == 0); diff --git a/kernel/arch/x86_64/PageTable.cpp b/kernel/arch/x86_64/PageTable.cpp index 7b54b2f4..22fdeadc 100644 --- a/kernel/arch/x86_64/PageTable.cpp +++ b/kernel/arch/x86_64/PageTable.cpp @@ -793,6 +793,65 @@ namespace Kernel invalidate_range(vaddr, page_count, true); } + void PageTable::remove_writable_from_range(vaddr_t vaddr, size_t size) + { + ASSERT(vaddr); + ASSERT(vaddr % PAGE_SIZE == 0); + + ASSERT(is_canonical(vaddr)); + ASSERT(is_canonical(vaddr + size - 1)); + + const vaddr_t uc_vaddr_start = uncanonicalize(vaddr); + const vaddr_t uc_vaddr_end = uncanonicalize(vaddr + size - 1); + + uint16_t pml4e = (uc_vaddr_start >> 39) & 0x1FF; + uint16_t pdpte = (uc_vaddr_start >> 30) & 0x1FF; + uint16_t pde = (uc_vaddr_start >> 21) & 0x1FF; + uint16_t pte = (uc_vaddr_start >> 12) & 0x1FF; + + const uint16_t e_pml4e = (uc_vaddr_end >> 39) & 0x1FF; + const uint16_t e_pdpte = (uc_vaddr_end >> 30) & 0x1FF; + const uint16_t e_pde = (uc_vaddr_end >> 21) & 0x1FF; + const uint16_t e_pte = (uc_vaddr_end >> 12) & 0x1FF; + + SpinLockGuard _(m_lock); + + const uint64_t* pml4 = P2V(m_highest_paging_struct); + for (; pml4e <= e_pml4e; pml4e++) + { + if (!(pml4[pml4e] & Flags::ReadWrite)) + continue; + const uint64_t* pdpt = P2V(pml4[pml4e] & s_page_addr_mask); + for (; pdpte < 512; pdpte++) + { + if (pml4e == e_pml4e && pdpte > e_pdpte) + break; + if (!(pdpt[pdpte] & Flags::ReadWrite)) + continue; + const uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask); + for (; pde < 512; pde++) + { + if (pml4e == e_pml4e && pdpte == e_pdpte && pde > e_pde) + break; + if (!(pd[pde] & Flags::ReadWrite)) + continue; + uint64_t* pt = P2V(pd[pde] & s_page_addr_mask); + for (; pte < 512; pte++) + { + if (pml4e == e_pml4e && pdpte == e_pdpte && pde == e_pde && pte > e_pte) + break; + pt[pte] &= ~static_cast(Flags::ReadWrite); + } + pte = 0; + } + pde = 0; + } + pdpte = 0; + } + + invalidate_range(vaddr, size / PAGE_SIZE, true); + } + uint64_t PageTable::get_page_data(vaddr_t vaddr) const { ASSERT(is_canonical(vaddr)); diff --git a/kernel/include/kernel/Memory/PageTable.h b/kernel/include/kernel/Memory/PageTable.h index fa18f5d8..53b07b6c 100644 --- a/kernel/include/kernel/Memory/PageTable.h +++ b/kernel/include/kernel/Memory/PageTable.h @@ -106,6 +106,8 @@ namespace Kernel void map_page_at(paddr_t, vaddr_t, flags_t, MemoryType = MemoryType::Normal, bool invalidate = true); void map_range_at(paddr_t, vaddr_t, size_t bytes, flags_t, MemoryType = MemoryType::Normal); + void remove_writable_from_range(vaddr_t, size_t); + paddr_t physical_address_of(vaddr_t) const; flags_t get_page_flags(vaddr_t) const;