Modify setup_mmu_range() to implement nested page table dynamically by setting PT_USER_MASK bit for all NPT pages because any nested page table accesses performed by the MMU are treated as user accesses. Suggested-by: Sean Christopherson <seanjc@xxxxxxxxxx> Signed-off-by: Manali Shukla <manali.shukla@xxxxxxx> --- lib/x86/vm.c | 25 +++++++++++++++++++++---- lib/x86/vm.h | 8 ++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/lib/x86/vm.c b/lib/x86/vm.c index 25a4f5f..46c36e5 100644 --- a/lib/x86/vm.c +++ b/lib/x86/vm.c @@ -140,16 +140,33 @@ bool any_present_pages(pgd_t *cr3, void *virt, size_t len) return false; } -static void setup_mmu_range(pgd_t *cr3, phys_addr_t start, size_t len) +void __setup_mmu_range(pgd_t *cr3, phys_addr_t start, size_t len, + unsigned long long mmu_flags) { + u64 orig_opt_mask = pte_opt_mask; u64 max = (u64)len + (u64)start; u64 phys = start; - while (phys + LARGE_PAGE_SIZE <= max) { - install_large_page(cr3, phys, (void *)(ulong)phys); - phys += LARGE_PAGE_SIZE; + /* + * Allocate 4k pages only for nested page table, PT_USER_MASK needs to + * be enabled only for nested pages. + */ + if (mmu_flags & IS_NESTED_MMU) + pte_opt_mask |= PT_USER_MASK; + + if (mmu_flags & USE_HUGEPAGES) { + while (phys + LARGE_PAGE_SIZE <= max) { + install_large_page(cr3, phys, (void *)(ulong)phys); + phys += LARGE_PAGE_SIZE; + } } install_pages(cr3, phys, max - phys, (void *)(ulong)phys); + + pte_opt_mask = orig_opt_mask; +} + +static inline void setup_mmu_range(pgd_t *cr3, phys_addr_t start, size_t len) { + __setup_mmu_range(cr3, start, len, USE_HUGEPAGES); } static void set_additional_vcpu_vmregs(struct vm_vcpu_info *info) diff --git a/lib/x86/vm.h b/lib/x86/vm.h index 4c6dff9..2df19e3 100644 --- a/lib/x86/vm.h +++ b/lib/x86/vm.h @@ -4,6 +4,10 @@ #include "processor.h" #include "asm/page.h" #include "asm/io.h" +#include "asm/bitops.h" + +#define IS_NESTED_MMU BIT(0) +#define USE_HUGEPAGES BIT(1) void setup_5level_page_table(void); @@ -37,6 +41,10 @@ pteval_t *install_pte(pgd_t *cr3, pteval_t *install_large_page(pgd_t *cr3, phys_addr_t phys, void *virt); void install_pages(pgd_t *cr3, phys_addr_t phys, size_t len, void *virt); bool any_present_pages(pgd_t *cr3, void *virt, size_t len); +void set_pte_opt_mask(void); +void reset_pte_opt_mask(void); +void __setup_mmu_range(pgd_t *cr3, phys_addr_t start, size_t len, + unsigned long long mmu_flags); static inline void *current_page_table(void) { -- 2.30.2