From bb11cce638499f3152a08842a30640ee016c7b61 Mon Sep 17 00:00:00 2001 From: Aaron LI Date: Sun, 6 Jun 2021 20:06:59 +0800 Subject: [PATCH] pmap: Implement pmap_npt_transform() for NVMM This function will transform an initialized pmap structure for use by NVMM's AMD SVM backend. AMD's NPT (nested page table), aka RVI (rapid virtualization indexing) implementation is more complete than Intel's EPT; it supports A/D bits and uses the same bits positions as native x86 page tables. So this function is a simplified version of pmap_ept_transform(). --- sys/platform/pc64/include/pmap.h | 1 + sys/platform/pc64/x86_64/pmap.c | 36 ++++++++++++++++++++++++++++++++ sys/vm/pmap.h | 1 + 3 files changed, 38 insertions(+) diff --git a/sys/platform/pc64/include/pmap.h b/sys/platform/pc64/include/pmap.h index ff631f5d01..0105d10aeb 100644 --- a/sys/platform/pc64/include/pmap.h +++ b/sys/platform/pc64/include/pmap.h @@ -238,6 +238,7 @@ RB_PROTOTYPE2(pv_entry_rb_tree, pv_entry, pv_entry, /* Types of pmap */ #define REGULAR_PMAP 0 /* Regular x86 */ #define EPT_PMAP 1 /* Intel EPT */ +#define NPT_PMAP 2 /* AMD NPT/RVI */ /* Bits indexes in pmap_bits */ enum { diff --git a/sys/platform/pc64/x86_64/pmap.c b/sys/platform/pc64/x86_64/pmap.c index c97677284d..24d7e635d5 100644 --- a/sys/platform/pc64/x86_64/pmap.c +++ b/sys/platform/pc64/x86_64/pmap.c @@ -2574,6 +2574,42 @@ pmap_ept_transform(pmap_t pmap, int flags) bzero(pmap->pm_pml4, PAGE_SIZE); } +/* + * Transform an initialized pmap for AMD NPT/RVI. + */ +void +pmap_npt_transform(pmap_t pmap, int flags) +{ + uint64_t protection_codes_npt[PROTECTION_CODES_SIZE] = { + [VM_PROT_NONE | VM_PROT_NONE | VM_PROT_NONE ] = 0, + [VM_PROT_READ | VM_PROT_NONE | VM_PROT_NONE ] = 0, + [VM_PROT_READ | VM_PROT_NONE | VM_PROT_EXECUTE] = 0, + [VM_PROT_NONE | VM_PROT_NONE | VM_PROT_EXECUTE] = 0, + [VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_NONE ] = + pmap_bits_default[PG_RW_IDX], + [VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_EXECUTE] = + pmap_bits_default[PG_RW_IDX], + [VM_PROT_READ | VM_PROT_WRITE | VM_PROT_NONE ] = + pmap_bits_default[PG_RW_IDX], + [VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE] = + pmap_bits_default[PG_RW_IDX], + }; + + pmap->pm_flags |= (flags | PMAP_HVM); + pmap->pmap_bits[TYPE_IDX] = NPT_PMAP; + /* Set PG_G and PG_NX bits to 0, similar to the EPT case above. */ + pmap->pmap_bits[PG_G_IDX] = 0; + pmap->pmap_bits[PG_NX_IDX] = 0; + + bcopy(protection_codes_npt, pmap->protection_codes, + sizeof(protection_codes_npt)); + + if (pmap->pm_pmlpv_iso != NULL) + bzero(pmap->pm_pml4, PAGE_SIZE * 2); + else + bzero(pmap->pm_pml4, PAGE_SIZE); +} + /* * This routine is called when various levels in the page table need to * be populated. This routine cannot fail. diff --git a/sys/vm/pmap.h b/sys/vm/pmap.h index 1c76386873..888445e38d 100644 --- a/sys/vm/pmap.h +++ b/sys/vm/pmap.h @@ -202,6 +202,7 @@ void pmap_puninit (pmap_t); void pmap_pinit0 (pmap_t); void pmap_pinit2 (pmap_t); void pmap_ept_transform (pmap_t, int); +void pmap_npt_transform (pmap_t, int); void pmap_protect (pmap_t, vm_offset_t, vm_offset_t, vm_prot_t); void pmap_remove_specific (pmap_t, vm_page_t); void pmap_qenter (vm_offset_t, struct vm_page **, int); -- 2.41.0