@@ -4,7 +4,7 @@
#include "alloc_page.h"
#include "smp.h"
-static pteval_t pte_opt_mask;
+static pteval_t pte_opt_mask, prev_pte_opt_mask;
pteval_t *install_pte(pgd_t *cr3,
int pte_level,
@@ -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 set_pte_opt_mask()
+{
+ prev_pte_opt_mask = pte_opt_mask;
+ pte_opt_mask = PT_USER_MASK;
+}
+
+void reset_pte_opt_mask()
+{
+ pte_opt_mask = prev_pte_opt_mask;
+}
+
+void setup_mmu_range(pgd_t *cr3, phys_addr_t start, size_t len, bool nested_mmu)
{
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;
- }
- install_pages(cr3, phys, max - phys, (void *)(ulong)phys);
+ if (nested_mmu == false) {
+ 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);
+ } else {
+ set_pte_opt_mask();
+ install_pages(cr3, phys, len, (void *)(ulong)phys);
+ reset_pte_opt_mask();
+ }
}
static void set_additional_vcpu_vmregs(struct vm_vcpu_info *info)
@@ -176,10 +193,10 @@ void *setup_mmu(phys_addr_t end_of_memory, void *opt_mask)
if (end_of_memory < (1ul << 32))
end_of_memory = (1ul << 32); /* map mmio 1:1 */
- setup_mmu_range(cr3, 0, end_of_memory);
+ setup_mmu_range(cr3, 0, end_of_memory, false);
#else
- setup_mmu_range(cr3, 0, (2ul << 30));
- setup_mmu_range(cr3, 3ul << 30, (1ul << 30));
+ setup_mmu_range(cr3, 0, (2ul << 30), false);
+ setup_mmu_range(cr3, 3ul << 30, (1ul << 30), false);
init_alloc_vpage((void*)(3ul << 30));
#endif
@@ -37,6 +37,9 @@ 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, bool nested_mmu);
static inline void *current_page_table(void)
{
If U/S bit is "0" for all page table entries, all these pages are considered as supervisor pages. By default, pte_opt_mask is set to "0" for all npt test cases, which sets U/S bit in all PTEs to "0". Any nested page table accesses performed by the MMU are treated as user acesses. So while implementing a nested page table dynamically, PT_USER_MASK needs to be enabled for all npt entries. set_mmu_range() function is improved based on above analysis. Suggested-by: Sean Christopherson <seanjc@google.com> Signed-off-by: Manali Shukla <manali.shukla@amd.com> --- lib/x86/vm.c | 37 +++++++++++++++++++++++++++---------- lib/x86/vm.h | 3 +++ 2 files changed, 30 insertions(+), 10 deletions(-)