The __virt_pg_map() helper function, used to build guest page tables, calls vm_is_gpa_protected() to determine the correct memory protection attributes for a given Guest Physical Address (GPA). This check works by looking up the GPA in the VM's defined physical memory regions. This approach fails when mapping the local APIC's base address (0xfee00000), as this is a Memory-Mapped I/O (MMIO) region, not part of the guest's RAM. Consequently, the lookup fails, and virt_pg_map() aborts with the error: "No vm physical memory at 0xfee00000". Fix this by introducing a special case for the APIC base address. When the physical address being mapped is APIC_DEFAULT_GPA, bypass the vm_is_gpa_protected() call. Since the APIC MMIO region is always treated as shared, explicitly set the shared bit in its Page Table Entry (PTE) and return immediately. This allows selftests to correctly map the APIC MMIO region, which is necessary for tests involving protected guests. Signed-off-by: Neeraj Upadhyay --- tools/testing/selftests/kvm/lib/x86/processor.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c index d72eb96efb7c..181f1943c4be 100644 --- a/tools/testing/selftests/kvm/lib/x86/processor.c +++ b/tools/testing/selftests/kvm/lib/x86/processor.c @@ -8,6 +8,7 @@ #include "kvm_util.h" #include "processor.h" #include "sev.h" +#include "apic.h" #ifndef NUM_INTERRUPTS #define NUM_INTERRUPTS 256 @@ -227,6 +228,11 @@ void __virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, int level) "PTE already present for 4k page at vaddr: 0x%lx", vaddr); *pte = PTE_PRESENT_MASK | PTE_WRITABLE_MASK | (paddr & PHYSICAL_PAGE_MASK); + if (paddr == APIC_DEFAULT_GPA) { + *pte |= vm->arch.s_bit; + return; + } + /* * Neither SEV nor TDX supports shared page tables, so only the final * leaf PTE needs manually set the C/S-bit. -- 2.34.1