forked from Bananymous/banan-os
Kernel: Add some bareboness functionality to map virtual addresses
This commit is contained in:
parent
d38470c8e2
commit
b3eeb6412f
|
@ -90,54 +90,8 @@ MMU::~MMU()
|
|||
|
||||
void MMU::map_page(uintptr_t address, uint8_t flags)
|
||||
{
|
||||
ASSERT((address >> 48) == 0);
|
||||
|
||||
ASSERT(flags & Flags::Present);
|
||||
bool should_invalidate = false;
|
||||
|
||||
address &= PAGE_MASK;
|
||||
|
||||
uint64_t pml4e = (address >> 39) & 0x1FF;
|
||||
uint64_t pdpte = (address >> 30) & 0x1FF;
|
||||
uint64_t pde = (address >> 21) & 0x1FF;
|
||||
uint64_t pte = (address >> 12) & 0x1FF;
|
||||
|
||||
uint64_t* pml4 = m_highest_paging_struct;
|
||||
if ((pml4[pml4e] & flags) != flags)
|
||||
{
|
||||
if (!(pml4[pml4e] & Flags::Present))
|
||||
pml4[pml4e] = (uint64_t)allocate_page_aligned_page();
|
||||
pml4[pml4e] = (pml4[pml4e] & PAGE_MASK) | flags;
|
||||
should_invalidate = true;
|
||||
}
|
||||
|
||||
uint64_t* pdpt = (uint64_t*)(pml4[pml4e] & PAGE_MASK);
|
||||
if ((pdpt[pdpte] & flags) != flags)
|
||||
{
|
||||
if (!(pdpt[pdpte] & Flags::Present))
|
||||
pdpt[pdpte] = (uint64_t)allocate_page_aligned_page();
|
||||
pdpt[pdpte] = (pdpt[pdpte] & PAGE_MASK) | flags;
|
||||
should_invalidate = true;
|
||||
}
|
||||
|
||||
uint64_t* pd = (uint64_t*)(pdpt[pdpte] & PAGE_MASK);
|
||||
if ((pd[pde] & flags) != flags)
|
||||
{
|
||||
if (!(pd[pde] & Flags::Present))
|
||||
pd[pde] = (uint64_t)allocate_page_aligned_page();
|
||||
pd[pde] = (pd[pde] & PAGE_MASK) | flags;
|
||||
should_invalidate = true;
|
||||
}
|
||||
|
||||
uint64_t* pt = (uint64_t*)(pd[pde] & PAGE_MASK);
|
||||
if ((pt[pte] & flags) != flags)
|
||||
{
|
||||
pt[pte] = address | flags;
|
||||
should_invalidate = true;
|
||||
}
|
||||
|
||||
if (should_invalidate)
|
||||
asm volatile("invlpg (%0)" :: "r"(address) : "memory");
|
||||
map_page_at(address, address, flags);
|
||||
}
|
||||
|
||||
void MMU::map_range(uintptr_t address, ptrdiff_t size, uint8_t flags)
|
||||
|
@ -195,3 +149,57 @@ void MMU::unmap_range(uintptr_t address, ptrdiff_t size)
|
|||
for (uintptr_t page = s_page; page <= e_page; page += PAGE_SIZE)
|
||||
unmap_page(page);
|
||||
}
|
||||
|
||||
void MMU::map_page_at(paddr_t paddr, vaddr_t vaddr, uint8_t flags)
|
||||
{
|
||||
ASSERT((paddr >> 48) == 0);
|
||||
ASSERT((vaddr >> 48) == 0);
|
||||
|
||||
ASSERT((paddr & ~PAGE_MASK) == 0);
|
||||
ASSERT((vaddr & ~PAGE_MASK) == 0);;
|
||||
|
||||
ASSERT(flags & Flags::Present);
|
||||
bool should_invalidate = false;
|
||||
|
||||
uint64_t pml4e = (vaddr >> 39) & 0x1FF;
|
||||
uint64_t pdpte = (vaddr >> 30) & 0x1FF;
|
||||
uint64_t pde = (vaddr >> 21) & 0x1FF;
|
||||
uint64_t pte = (vaddr >> 12) & 0x1FF;
|
||||
|
||||
uint64_t* pml4 = m_highest_paging_struct;
|
||||
if ((pml4[pml4e] & flags) != flags)
|
||||
{
|
||||
if (!(pml4[pml4e] & Flags::Present))
|
||||
pml4[pml4e] = (uint64_t)allocate_page_aligned_page();
|
||||
pml4[pml4e] = (pml4[pml4e] & PAGE_MASK) | flags;
|
||||
should_invalidate = true;
|
||||
}
|
||||
|
||||
uint64_t* pdpt = (uint64_t*)(pml4[pml4e] & PAGE_MASK);
|
||||
if ((pdpt[pdpte] & flags) != flags)
|
||||
{
|
||||
if (!(pdpt[pdpte] & Flags::Present))
|
||||
pdpt[pdpte] = (uint64_t)allocate_page_aligned_page();
|
||||
pdpt[pdpte] = (pdpt[pdpte] & PAGE_MASK) | flags;
|
||||
should_invalidate = true;
|
||||
}
|
||||
|
||||
uint64_t* pd = (uint64_t*)(pdpt[pdpte] & PAGE_MASK);
|
||||
if ((pd[pde] & flags) != flags)
|
||||
{
|
||||
if (!(pd[pde] & Flags::Present))
|
||||
pd[pde] = (uint64_t)allocate_page_aligned_page();
|
||||
pd[pde] = (pd[pde] & PAGE_MASK) | flags;
|
||||
should_invalidate = true;
|
||||
}
|
||||
|
||||
uint64_t* pt = (uint64_t*)(pd[pde] & PAGE_MASK);
|
||||
if ((pt[pte] & flags) != flags)
|
||||
{
|
||||
pt[pte] = paddr | flags;
|
||||
should_invalidate = true;
|
||||
}
|
||||
|
||||
if (should_invalidate)
|
||||
asm volatile("movq %0, %%cr3" :: "r"(m_highest_paging_struct));
|
||||
}
|
||||
|
|
|
@ -59,8 +59,8 @@ namespace Kernel::Memory
|
|||
static void initialize();
|
||||
static Heap& get();
|
||||
|
||||
paddr_t take_mapped_page(uint8_t);
|
||||
void return_mapped_page(paddr_t);
|
||||
paddr_t take_free_page();
|
||||
void release_page(paddr_t);
|
||||
|
||||
private:
|
||||
Heap() = default;
|
||||
|
|
|
@ -13,6 +13,9 @@ public:
|
|||
UserSupervisor = 4,
|
||||
};
|
||||
|
||||
using vaddr_t = uintptr_t;
|
||||
using paddr_t = uintptr_t;
|
||||
|
||||
public:
|
||||
static void intialize();
|
||||
static MMU& get();
|
||||
|
@ -26,6 +29,8 @@ public:
|
|||
void unmap_page(uintptr_t);
|
||||
void unmap_range(uintptr_t, ptrdiff_t);
|
||||
|
||||
void map_page_at(paddr_t, vaddr_t, uint8_t);
|
||||
|
||||
private:
|
||||
uint64_t* m_highest_paging_struct;
|
||||
};
|
||||
|
|
|
@ -158,26 +158,21 @@ namespace Kernel::Memory
|
|||
dprintln("Total RAM {}.{} MB", total / (1 << 20), total % (1 << 20) * 1000 / (1 << 20));
|
||||
}
|
||||
|
||||
paddr_t Heap::take_mapped_page(uint8_t flags)
|
||||
paddr_t Heap::take_free_page()
|
||||
{
|
||||
for (auto& range : m_physical_ranges)
|
||||
{
|
||||
if (paddr_t page = range.reserve_page(); page != PhysicalRange::invalid)
|
||||
{
|
||||
MMU::get().map_page(page, flags);
|
||||
return page;
|
||||
}
|
||||
}
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
void Heap::return_mapped_page(paddr_t addr)
|
||||
void Heap::release_page(paddr_t addr)
|
||||
{
|
||||
for (auto& range : m_physical_ranges)
|
||||
{
|
||||
if (range.contains(addr))
|
||||
{
|
||||
MMU::get().unmap_page(addr);
|
||||
range.release_page(addr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue