fix(VMM): use correct APTable encoding for table descriptors

fix(VMM): use correct APTable encoding for table descriptors

fix(vmm): changed flags to match ARMv8
This commit is contained in:
karina
2026-05-03 10:11:43 +04:00
parent a3dc3054b8
commit 359eaeb405
4 changed files with 34 additions and 15 deletions
+1 -1
View File
@@ -30,4 +30,4 @@ set_target_properties(BOOTAA64 PROPERTIES
SUFFIX ".EFI" SUFFIX ".EFI"
OUTPUT_NAME "BOOTAA64" OUTPUT_NAME "BOOTAA64"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/efi_bin" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/efi_bin"
) )
+3 -3
View File
@@ -139,8 +139,8 @@ static efi_status_t load_elf_segments(efi_physical_address_t kernel_addr, efi_fi
if (phdr->p_type != PT_LOAD) continue; if (phdr->p_type != PT_LOAD) continue;
uintn_t pages = (phdr->p_memsz + 0xFFF) / 0x1000; uintn_t pages = (phdr->p_memsz + 0xFFF) / 0x1000;
efi_physical_address_t segment_addr = phdr->p_paddr; efi_physical_address_t segment_addr = phdr->p_paddr;
efi_status_t status = gBS->AllocatePages(AllocateAddress, EfiLoaderData, pages, &segment_addr); efi_status_t status = gBS->AllocatePages(AllocateAddress, EfiLoaderData, pages, &segment_addr);
if (EFI_ERROR(status)) { if (EFI_ERROR(status)) {
@@ -279,4 +279,4 @@ efi_status_t bootloader_main(void) {
kernel_main(boot_info); kernel_main(boot_info);
return EFI_SUCCESS; return EFI_SUCCESS;
} }
+18 -9
View File
@@ -4,19 +4,28 @@
#include "../Common/bootinfo.h" #include "../Common/bootinfo.h"
enum VMPTEFlags { enum VMPTEFlags {
kPTEValid = (1ULL << 0), // 1 = Present (Will page fault if 0) // Descriptor type (bits [1:0])
kPTETable = (1ULL << 1), // 1 = Valid for L0/L1/L2 Directory kPTEValid = (1ULL << 0), // 1 = Valid (fault if 0)
kPTEPage = (1ULL << 1), // 1 = Valid for L3 Page (Same bit) kPTETable = (1ULL << 1), // For L0/L1/L2: table descriptor (bits[1:0]=11)
kPTEPage = (1ULL << 1), // For L3: page descriptor (same bit, bits[1:0]=11)
kPTENormalMem = (0ULL << 2), // Cached, Normal RAM // MAIR attribute index (bits [4:2])
kPTEDeviceMem = (1ULL << 2), // Uncached, MMIO Device kPTENormalMem = (0ULL << 2), // AttrIndx 0 → MAIR[7:0] = 0xFF (Normal, WB Cacheable)
kPTEDeviceMem = (1ULL << 2), // AttrIndx 1 → MAIR[15:8] = 0x00 (Device-nGnRnE)
kPTEAccessRW = (0ULL << 6), // Read/Write // Leaf entry AP[2:1] (bits [7:6]):
kPTEAccessRO = (1ULL << 6), // Read-Only // AP[1] (bit 6): 0 = EL0 blocked, 1 = EL0 allowed
kPTEUser = (1ULL << 7), // 1 = EL0, 0 = EL1 // AP[2] (bit 7): 0 = Read/Write, 1 = Read-only
kPTEUser = (1ULL << 6), // AP[1]=1: allow EL0 access
kPTEAccessRW = (0ULL << 7), // AP[2]=0: writable for permitted levels
kPTEAccessRO = (1ULL << 7), // AP[2]=1: read-only for all levels
// Table descriptor APTable[1:0] (bits [62:61]):
// 00 = no restriction, 01 = block EL0, 10 = reserved, 11 = read-only for all
kPTETableNoEL0 = (1ULL << 61), // APTable[0]=1: prevent EL0 table walk
kPTEInnerShare = (3ULL << 8), // Inner Shareable (SMP safe) kPTEInnerShare = (3ULL << 8), // Inner Shareable (SMP safe)
kPTEAccessFlag = (1ULL << 10), // CPU access tracking (MUST be 1 to avoid faults) kPTEAccessFlag = (1ULL << 10), // Access Flag (MUST be 1 to avoid faults)
kPTEPrivNX = (1ULL << 53), // PXN: Privileged Execute Never kPTEPrivNX = (1ULL << 53), // PXN: Privileged Execute Never
kPTEUserNX = (1ULL << 54) // UXN: Unprivileged Execute Never kPTEUserNX = (1ULL << 54) // UXN: Unprivileged Execute Never
}; };
+12 -2
View File
@@ -38,7 +38,11 @@ static inline Address* GetOrAllocateTable(Address* parentTable, Size index, UInt
return newTableVirt; return newTableVirt;
} }
parentTable[index] |= (flags & kPTEUser); // if user access requested, clear APTable bit to allow EL0 table walk.
// otherwise leave APTable as-is (kernel-only tables keep kPTETableNoEL0).
if (flags & kPTEUser) {
parentTable[index] &= ~kPTETableNoEL0;
}
Address physAddress = GetPTEAddress(parentTable[index]); Address physAddress = GetPTEAddress(parentTable[index]);
return GetVirtualTable(physAddress); return GetVirtualTable(physAddress);
@@ -83,7 +87,13 @@ Address* VMMMapPage(Address* l0Table, Address phys, Address virt, UInt64 flags)
Address* l0Virt = l0Table; Address* l0Virt = l0Table;
if (isInitialized) l0Virt = (Address*)VMPhysToHHDM((Address)l0Table); if (isInitialized) l0Virt = (Address*)VMPhysToHHDM((Address)l0Table);
UInt64 directoryFlags = kPTEValid | kPTETable | (flags & kPTEUser); // build directory flags for table descriptors
// APTable=01 (kPTETableNoEL0) blocks EL0 entirely - used for kernel-only subtrees.
// APTable=00 allows EL0 access by leaf page permissions - used for user mappings.
UInt64 directoryFlags = kPTEValid | kPTETable;
if (!(flags & kPTEUser)) {
directoryFlags |= kPTETableNoEL0;
}
Address* l1Virt = GetOrAllocateTable(l0Virt, l0Index, flags, directoryFlags); Address* l1Virt = GetOrAllocateTable(l0Virt, l0Index, flags, directoryFlags);
if (!l1Virt) return nullptr; if (!l1Virt) return nullptr;