From 359eaeb4053fd5c5ac0fd43e255d650b6dcf8072 Mon Sep 17 00:00:00 2001 From: karina Date: Sun, 3 May 2026 10:11:43 +0400 Subject: [PATCH] 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 --- Bootloader/CMakeLists.txt | 2 +- Bootloader/Source/main.c | 6 +++--- Kernel/Include/VM/VMM.h | 27 ++++++++++++++++++--------- Kernel/Source/VM/VMM.c | 14 ++++++++++++-- 4 files changed, 34 insertions(+), 15 deletions(-) diff --git a/Bootloader/CMakeLists.txt b/Bootloader/CMakeLists.txt index 2a6c1f0..b54cb4a 100644 --- a/Bootloader/CMakeLists.txt +++ b/Bootloader/CMakeLists.txt @@ -30,4 +30,4 @@ set_target_properties(BOOTAA64 PROPERTIES SUFFIX ".EFI" OUTPUT_NAME "BOOTAA64" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/efi_bin" -) \ No newline at end of file +) diff --git a/Bootloader/Source/main.c b/Bootloader/Source/main.c index 2a6df3d..d08f24b 100644 --- a/Bootloader/Source/main.c +++ b/Bootloader/Source/main.c @@ -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; 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); if (EFI_ERROR(status)) { @@ -279,4 +279,4 @@ efi_status_t bootloader_main(void) { kernel_main(boot_info); return EFI_SUCCESS; -} \ No newline at end of file +} diff --git a/Kernel/Include/VM/VMM.h b/Kernel/Include/VM/VMM.h index 568763d..90301f6 100644 --- a/Kernel/Include/VM/VMM.h +++ b/Kernel/Include/VM/VMM.h @@ -4,19 +4,28 @@ #include "../Common/bootinfo.h" enum VMPTEFlags { - kPTEValid = (1ULL << 0), // 1 = Present (Will page fault if 0) - kPTETable = (1ULL << 1), // 1 = Valid for L0/L1/L2 Directory - kPTEPage = (1ULL << 1), // 1 = Valid for L3 Page (Same bit) + // Descriptor type (bits [1:0]) + kPTEValid = (1ULL << 0), // 1 = Valid (fault if 0) + 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 - kPTEDeviceMem = (1ULL << 2), // Uncached, MMIO Device + // MAIR attribute index (bits [4:2]) + 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 - kPTEAccessRO = (1ULL << 6), // Read-Only - kPTEUser = (1ULL << 7), // 1 = EL0, 0 = EL1 + // Leaf entry AP[2:1] (bits [7:6]): + // AP[1] (bit 6): 0 = EL0 blocked, 1 = EL0 allowed + // 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) - 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 kPTEUserNX = (1ULL << 54) // UXN: Unprivileged Execute Never }; diff --git a/Kernel/Source/VM/VMM.c b/Kernel/Source/VM/VMM.c index d0af705..0756043 100644 --- a/Kernel/Source/VM/VMM.c +++ b/Kernel/Source/VM/VMM.c @@ -38,7 +38,11 @@ static inline Address* GetOrAllocateTable(Address* parentTable, Size index, UInt 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]); return GetVirtualTable(physAddress); @@ -83,7 +87,13 @@ Address* VMMMapPage(Address* l0Table, Address phys, Address virt, UInt64 flags) Address* l0Virt = 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); if (!l1Virt) return nullptr;