ptos/amd64+hal: Add page mapping interface
Signed-off-by: Chloe M <chloe@mensia.org>
This commit is contained in:
@@ -7,8 +7,169 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <hal/mmu.h>
|
#include <hal/mmu.h>
|
||||||
|
#include <machine/mmu.h>
|
||||||
|
#include <machine/tlb.h>
|
||||||
|
#include <mm/pm.h>
|
||||||
|
#include <mm/vm.h>
|
||||||
|
#include <ke/bugcheck.h>
|
||||||
#include <ptdef.h>
|
#include <ptdef.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Valid paging structure levels
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
PAGEMAP_PML1,
|
||||||
|
PAGEMAP_PML2,
|
||||||
|
PAGEMAP_PML3,
|
||||||
|
PAGEMAP_PML4
|
||||||
|
} PAGEMAP_LEVEL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns true if the given page size is valid
|
||||||
|
*
|
||||||
|
* @PageSize: Page size to check
|
||||||
|
*/
|
||||||
|
ALWAYS_INLINE static inline BOOLEAN
|
||||||
|
MmuPageSizeValid(MMU_PAGESIZE PageSize)
|
||||||
|
{
|
||||||
|
switch (PageSize) {
|
||||||
|
case PAGESIZE_4K:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Obtain the pagemap top-level index
|
||||||
|
*
|
||||||
|
* XXX: In future revisions we should read CR4 and determine
|
||||||
|
* if 57-bit linear addresses are enabled for 5-level
|
||||||
|
* paging.
|
||||||
|
*/
|
||||||
|
ALWAYS_INLINE static inline PAGEMAP_LEVEL
|
||||||
|
MmuTopLevel(VOID)
|
||||||
|
{
|
||||||
|
return PAGEMAP_PML4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Obtain PTE flags from MI page protection
|
||||||
|
* flags
|
||||||
|
*
|
||||||
|
* @Prot: Protection flags to convert
|
||||||
|
*/
|
||||||
|
static USIZE
|
||||||
|
MmuProtToPte(MM_PROT Prot)
|
||||||
|
{
|
||||||
|
USIZE PteFlags = PTE_P | PTE_NX;
|
||||||
|
|
||||||
|
if (ISSET(Prot, PAGE_WRITE))
|
||||||
|
PteFlags |= PTE_RW;
|
||||||
|
if (ISSET(Prot, PAGE_EXEC))
|
||||||
|
PteFlags &= ~PTE_NX;
|
||||||
|
if (ISSET(Prot, PAGE_USER))
|
||||||
|
PteFlags |= PTE_US;
|
||||||
|
|
||||||
|
return PteFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extract a pagemap index from a virtual address for a given
|
||||||
|
* level.
|
||||||
|
*
|
||||||
|
* @VirtualBase: Virtual base address
|
||||||
|
* @Level: Pagemap level to get index of
|
||||||
|
*
|
||||||
|
* XXX: Caller should ensure the page alignment of @VirtualBase
|
||||||
|
*/
|
||||||
|
static inline USHORT
|
||||||
|
MmuPageMapIndex(UPTR VirtualBase, PAGEMAP_LEVEL Level)
|
||||||
|
{
|
||||||
|
switch (Level) {
|
||||||
|
case PAGEMAP_PML1:
|
||||||
|
return (VirtualBase >> 12) & 0x1FF;
|
||||||
|
case PAGEMAP_PML2:
|
||||||
|
return (VirtualBase >> 21) & 0x1FF;
|
||||||
|
case PAGEMAP_PML3:
|
||||||
|
return (VirtualBase >> 30) & 0x1FF;
|
||||||
|
case PAGEMAP_PML4:
|
||||||
|
return (VirtualBase >> 39) & 0x1FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This should not happen */
|
||||||
|
KeBugCheck(
|
||||||
|
BUGCHECK_IO_ERROR,
|
||||||
|
"bad pagemap level in MmuPageMapIndex()\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extract a pagemap at a specific level
|
||||||
|
*
|
||||||
|
* @Vas: Virtual address space to translate from
|
||||||
|
* @VirtualBase: Virtual base address
|
||||||
|
* @Level: Level to extract
|
||||||
|
* @Alloc: If true, allocate new level
|
||||||
|
*
|
||||||
|
* Returns the pogemap level base on success, otherwise NULL
|
||||||
|
* on failure.
|
||||||
|
*
|
||||||
|
* XXX: Caller should ensure the page alignment of @VirtualBase
|
||||||
|
*/
|
||||||
|
static UPTR *
|
||||||
|
MmuPageMapExtract(MMU_VAS *Vas, UPTR VirtualBase, PAGEMAP_LEVEL Level, BOOLEAN Alloc)
|
||||||
|
{
|
||||||
|
UPTR *PageMap;
|
||||||
|
PAGEMAP_LEVEL CurrentLevel;
|
||||||
|
MM_PFN Pfn;
|
||||||
|
UPTR PhysicalBase;
|
||||||
|
USIZE Index;
|
||||||
|
|
||||||
|
if (Vas == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the top-level */
|
||||||
|
CurrentLevel = MmuTopLevel();
|
||||||
|
PageMap = PMA_TO_VMA((Vas->Cr3 & PTE_ADDR_MASK));
|
||||||
|
|
||||||
|
/* Walk through each level */
|
||||||
|
while (CurrentLevel > Level) {
|
||||||
|
Index = MmuPageMapIndex(VirtualBase, CurrentLevel);
|
||||||
|
|
||||||
|
/* Is this entry already present? */
|
||||||
|
if (ISSET(PageMap[Index], PTE_P)) {
|
||||||
|
PageMap = PMA_TO_VMA((PageMap[Index] & PTE_ADDR_MASK));
|
||||||
|
--CurrentLevel;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Alloc) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now we allocate a level for this entry
|
||||||
|
*
|
||||||
|
* XXX: We need to consider how we'll clean up when unmapping pages
|
||||||
|
* as the destruction of a virtual address space will end up
|
||||||
|
* leaking memory if this point is reached.
|
||||||
|
*/
|
||||||
|
Pfn = MmRequestFrame();
|
||||||
|
if (Pfn == PFN_ERROR) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
PhysicalBase = PFN_TO_ADDRESS(Pfn);
|
||||||
|
PageMap[Index] = PhysicalBase | (PTE_P | PTE_RW | PTE_US);
|
||||||
|
PageMap = PMA_TO_VMA(PhysicalBase);
|
||||||
|
--CurrentLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PageMap;
|
||||||
|
}
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
HalMmuReadVas(MMU_VAS *Result)
|
HalMmuReadVas(MMU_VAS *Result)
|
||||||
{
|
{
|
||||||
@@ -38,3 +199,35 @@ HalMmuWriteVas(const MMU_VAS *Vas)
|
|||||||
: "memory"
|
: "memory"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PT_STATUS
|
||||||
|
HalMmuMapPage(
|
||||||
|
MMU_VAS *Vas, UPTR VirtualBase,
|
||||||
|
UPTR PhysicalBase, MM_PROT Prot,
|
||||||
|
MMU_PAGESIZE PageSize)
|
||||||
|
{
|
||||||
|
UPTR *PageTable;
|
||||||
|
USIZE PageTableIndex;
|
||||||
|
USIZE PteFlags;
|
||||||
|
|
||||||
|
if (Vas == NULL) {
|
||||||
|
return STATUS_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!MmuPageSizeValid(PageSize)) {
|
||||||
|
return STATUS_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
PageTable = MmuPageMapExtract(Vas, VirtualBase, PAGEMAP_PML1, true);
|
||||||
|
if (PageTable == NULL) {
|
||||||
|
return STATUS_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
PageTableIndex = MmuPageMapIndex(VirtualBase, PAGEMAP_PML1);
|
||||||
|
PteFlags = MmuProtToPte(Prot);
|
||||||
|
|
||||||
|
/* Map the memory and flush the TLB entry */
|
||||||
|
PageTable[PageTableIndex] = PhysicalBase | PteFlags;
|
||||||
|
MdTlbFlushSingle(VirtualBase);
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,9 +9,19 @@
|
|||||||
#ifndef _HAL_MMU_H_
|
#ifndef _HAL_MMU_H_
|
||||||
#define _HAL_MMU_H_ 1
|
#define _HAL_MMU_H_ 1
|
||||||
|
|
||||||
|
#include <ptapi/ptmm.h>
|
||||||
|
#include <ptapi/status.h>
|
||||||
#include <hal/vas.h>
|
#include <hal/vas.h>
|
||||||
#include <ptdef.h>
|
#include <ptdef.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Represents valid page sizes that can be mapped
|
||||||
|
* with.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
PAGESIZE_4K
|
||||||
|
} MMU_PAGESIZE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read the current virtual address space into an
|
* Read the current virtual address space into an
|
||||||
* MMU_VAS descriptor.
|
* MMU_VAS descriptor.
|
||||||
@@ -28,4 +38,18 @@ VOID HalMmuReadVas(MMU_VAS *Result);
|
|||||||
*/
|
*/
|
||||||
VOID HalMmuWriteVas(const MMU_VAS *Vas);
|
VOID HalMmuWriteVas(const MMU_VAS *Vas);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Map a single page of memory
|
||||||
|
*
|
||||||
|
* @Vas: Virtual address space to map within
|
||||||
|
* @VirtualBase: Virtual address base to map
|
||||||
|
* @Prot: Protection flags
|
||||||
|
* @PageSize: Pagesize to map as
|
||||||
|
*/
|
||||||
|
PT_STATUS HalMmuMapPage(
|
||||||
|
MMU_VAS *Vas, UPTR VirtualBase,
|
||||||
|
UPTR PhysicalBase, MM_PROT Prot,
|
||||||
|
MMU_PAGESIZE PageSize
|
||||||
|
);
|
||||||
|
|
||||||
#endif /* !_HAL_MMU_H_ */
|
#endif /* !_HAL_MMU_H_ */
|
||||||
|
|||||||
Reference in New Issue
Block a user