Skip to content

Commit

Permalink
[mmu][hypervisor] Support for more memory types
Browse files Browse the repository at this point in the history
Add support for uncached, uncached device, and write-combining to
stage-2 page tables on arm64 and EPT page tables on x86-64.

Test: Ran 'guest launch zircon_guest', 'hypervisor-test',
      'machina_unittests', and 'k ut hypervisor'.
Change-Id: I9d8e55c8357384e04a099c1cb25ac977027ed239
  • Loading branch information
abdulla authored and CQ bot account: [email protected] committed Aug 9, 2018
1 parent 3cab79f commit ffd5fb5
Show file tree
Hide file tree
Showing 6 changed files with 220 additions and 77 deletions.
2 changes: 2 additions & 0 deletions kernel/arch/arm64/include/arch/arm64/mmu.h
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,8 @@
#define MMU_S2_PTE_ATTR_ATTR_INDEX_MASK BM(2, 4, 0xf)
/* Normal, Outer Write-Back Cacheable, Inner Write-Back Cacheable. */
#define MMU_S2_PTE_ATTR_NORMAL_MEMORY BM(2, 4, 0xf)
/* Normal, Outer Non-cacheable, Inner Non-cacheable. */
#define MMU_S2_PTE_ATTR_NORMAL_UNCACHED BM(2, 4, 0x5)
/* Device, Device-nGnRnE memory. */
#define MMU_S2_PTE_ATTR_STRONGLY_ORDERED BM(2, 4, 0x0)
/* Device, Device-nGnRE memory. */
Expand Down
46 changes: 36 additions & 10 deletions kernel/arch/arm64/mmu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,7 @@ static pte_t mmu_flags_to_s1_pte_attr(uint flags) {
attr |= MMU_PTE_ATTR_DEVICE;
break;
default:
// Invalid user-supplied flag.
DEBUG_ASSERT(false);
return ZX_ERR_INVALID_ARGS;
PANIC_UNIMPLEMENTED;
}

switch (flags & (ARCH_MMU_FLAG_PERM_USER | ARCH_MMU_FLAG_PERM_WRITE)) {
Expand All @@ -180,7 +178,6 @@ static pte_t mmu_flags_to_s1_pte_attr(uint flags) {
if (!(flags & ARCH_MMU_FLAG_PERM_EXECUTE)) {
attr |= MMU_PTE_ATTR_UXN | MMU_PTE_ATTR_PXN;
}

if (flags & ARCH_MMU_FLAG_NS) {
attr |= MMU_PTE_ATTR_NON_SECURE;
}
Expand All @@ -200,10 +197,12 @@ static void s1_pte_attr_to_mmu_flags(pte_t pte, uint* mmu_flags) {
*mmu_flags |= ARCH_MMU_FLAG_WRITE_COMBINING;
break;
case MMU_PTE_ATTR_NORMAL_MEMORY:
*mmu_flags |= ARCH_MMU_FLAG_CACHED;
break;
default:
PANIC_UNIMPLEMENTED;
}

*mmu_flags |= ARCH_MMU_FLAG_PERM_READ;
switch (pte & MMU_PTE_ATTR_AP_MASK) {
case MMU_PTE_ATTR_AP_P_RW_U_NA:
Expand All @@ -218,6 +217,7 @@ static void s1_pte_attr_to_mmu_flags(pte_t pte, uint* mmu_flags) {
*mmu_flags |= ARCH_MMU_FLAG_PERM_USER;
break;
}

if (!((pte & MMU_PTE_ATTR_UXN) && (pte & MMU_PTE_ATTR_PXN))) {
*mmu_flags |= ARCH_MMU_FLAG_PERM_EXECUTE;
}
Expand All @@ -227,16 +227,30 @@ static void s1_pte_attr_to_mmu_flags(pte_t pte, uint* mmu_flags) {
}

static pte_t mmu_flags_to_s2_pte_attr(uint flags) {
DEBUG_ASSERT((flags & ARCH_MMU_FLAG_CACHE_MASK) == ARCH_MMU_FLAG_CACHED);
// Only the inner-shareable, normal memory type is supported.
pte_t attr = MMU_PTE_ATTR_AF | MMU_PTE_ATTR_SH_INNER_SHAREABLE | MMU_S2_PTE_ATTR_NORMAL_MEMORY;
pte_t attr = MMU_PTE_ATTR_AF;

switch (flags & ARCH_MMU_FLAG_CACHE_MASK) {
case ARCH_MMU_FLAG_CACHED:
attr |= MMU_S2_PTE_ATTR_NORMAL_MEMORY | MMU_PTE_ATTR_SH_INNER_SHAREABLE;
break;
case ARCH_MMU_FLAG_WRITE_COMBINING:
attr |= MMU_S2_PTE_ATTR_NORMAL_UNCACHED | MMU_PTE_ATTR_SH_INNER_SHAREABLE;
break;
case ARCH_MMU_FLAG_UNCACHED:
attr |= MMU_S2_PTE_ATTR_STRONGLY_ORDERED;
break;
case ARCH_MMU_FLAG_UNCACHED_DEVICE:
attr |= MMU_S2_PTE_ATTR_DEVICE;
break;
default:
PANIC_UNIMPLEMENTED;
}

if (flags & ARCH_MMU_FLAG_PERM_WRITE) {
attr |= MMU_S2_PTE_ATTR_S2AP_RW;
} else {
attr |= MMU_S2_PTE_ATTR_S2AP_RO;
}

if (!(flags & ARCH_MMU_FLAG_PERM_EXECUTE)) {
attr |= MMU_S2_PTE_ATTR_XN;
}
Expand All @@ -245,8 +259,20 @@ static pte_t mmu_flags_to_s2_pte_attr(uint flags) {
}

static void s2_pte_attr_to_mmu_flags(pte_t pte, uint* mmu_flags) {
// Only the inner-shareable, normal memory type is supported.
if ((pte & MMU_S2_PTE_ATTR_ATTR_INDEX_MASK) != MMU_S2_PTE_ATTR_NORMAL_MEMORY) {
switch (pte & MMU_S2_PTE_ATTR_ATTR_INDEX_MASK) {
case MMU_S2_PTE_ATTR_STRONGLY_ORDERED:
*mmu_flags |= ARCH_MMU_FLAG_UNCACHED;
break;
case MMU_S2_PTE_ATTR_DEVICE:
*mmu_flags |= ARCH_MMU_FLAG_UNCACHED_DEVICE;
break;
case MMU_S2_PTE_ATTR_NORMAL_UNCACHED:
*mmu_flags |= ARCH_MMU_FLAG_WRITE_COMBINING;
break;
case MMU_S2_PTE_ATTR_NORMAL_MEMORY:
*mmu_flags |= ARCH_MMU_FLAG_CACHED;
break;
default:
PANIC_UNIMPLEMENTED;
}

Expand Down
2 changes: 1 addition & 1 deletion kernel/arch/x86/hypervisor/vcpu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ static uint64_t ept_pointer(paddr_t pml4_address) {
return
// Physical address of the PML4 page, page aligned.
pml4_address |
// Use write back memory.
// Use write-back memory type for paging structures.
VMX_MEMORY_TYPE_WRITE_BACK << 0 |
// Page walk length of 4 (defined as N minus 1).
3u << 3;
Expand Down
30 changes: 17 additions & 13 deletions kernel/arch/x86/include/arch/x86/mmu.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,27 @@
/* top level defines for the x86 mmu */
/* NOTE: the top part can be included from assembly */

#define X86_EPT_R (1u << 0) /* R Read */
#define X86_EPT_W (1u << 1) /* W Write */
#define X86_EPT_X (1u << 2) /* X Execute */
#define X86_EPT_A (1u << 8) /* A Accessed */
#define X86_EPT_D (1u << 9) /* D Dirty */
#define X86_EPT_R (1u << 0) /* R Read */
#define X86_EPT_W (1u << 1) /* W Write */
#define X86_EPT_X (1u << 2) /* X Execute */
#define X86_EPT_A (1u << 8) /* A Accessed */
#define X86_EPT_D (1u << 9) /* D Dirty */

/* From Volume 3, Section 28.2.6: EPT and Memory Typing */
#define X86_EPT_WB (6u << 3) /* WB Write-back memory type */
#define X86_EPT_MEMORY_TYPE_MASK (7u << 3)
#define X86_EPT_UC (0u << 3) /* UC Uncached memory type */
#define X86_EPT_WC (1u << 3) /* WC Write-combining memory type */
#define X86_EPT_WT (4u << 3) /* WT Write-through memory type */
#define X86_EPT_WP (5u << 3) /* WP Write-protected memory type */
#define X86_EPT_WB (6u << 3) /* WB Write-back memory type */

/* Page Attribute Table memory types, defined in Table 11-10 of Intel 3A */
#define X86_PAT_UC 0x00 /* Uncached */
#define X86_PAT_WC 0x01 /* Write-combining */
#define X86_PAT_WT 0x04 /* Write-through */
#define X86_PAT_WP 0x05 /* Write protected */
#define X86_PAT_WB 0X06 /* Write-back */
#define X86_PAT_UC_ 0x07 /* Weakly Uncached (can be overrided by a
* WC MTRR setting) */
#define X86_PAT_UC 0x00 /* Uncached */
#define X86_PAT_WC 0x01 /* Write-combining */
#define X86_PAT_WT 0x04 /* Write-through */
#define X86_PAT_WP 0x05 /* Write protected */
#define X86_PAT_WB 0X06 /* Write-back */
#define X86_PAT_UC_ 0x07 /* Weakly Uncached (can be overridden by a WC MTRR setting) */

/* Our configuration for the PAT indexes. This must be kept in sync with the
* selector definitions below it. For safety, it is important to ensure that
Expand Down
81 changes: 55 additions & 26 deletions kernel/arch/x86/mmu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,18 +239,18 @@ X86PageTableBase::PtFlags X86PageTableMmu::terminal_flags(PageTableLevel level,
uint flags) {
X86PageTableBase::PtFlags terminal_flags = 0;

if (flags & ARCH_MMU_FLAG_PERM_WRITE)
if (flags & ARCH_MMU_FLAG_PERM_WRITE) {
terminal_flags |= X86_MMU_PG_RW;

if (flags & ARCH_MMU_FLAG_PERM_USER)
}
if (flags & ARCH_MMU_FLAG_PERM_USER) {
terminal_flags |= X86_MMU_PG_U;

}
if (use_global_mappings_) {
terminal_flags |= X86_MMU_PG_G;
}

if (!(flags & ARCH_MMU_FLAG_PERM_EXECUTE))
if (!(flags & ARCH_MMU_FLAG_PERM_EXECUTE)) {
terminal_flags |= X86_MMU_PG_NX;
}

if (level > 0) {
switch (flags & ARCH_MMU_FLAG_CACHE_MASK) {
Expand Down Expand Up @@ -313,14 +313,15 @@ void X86PageTableMmu::TlbInvalidate(PendingTlbInvalidation* pending) {
uint X86PageTableMmu::pt_flags_to_mmu_flags(PtFlags flags, PageTableLevel level) {
uint mmu_flags = ARCH_MMU_FLAG_PERM_READ;

if (flags & X86_MMU_PG_RW)
if (flags & X86_MMU_PG_RW) {
mmu_flags |= ARCH_MMU_FLAG_PERM_WRITE;

if (flags & X86_MMU_PG_U)
}
if (flags & X86_MMU_PG_U) {
mmu_flags |= ARCH_MMU_FLAG_PERM_USER;

if (!(flags & X86_MMU_PG_NX))
}
if (!(flags & X86_MMU_PG_NX)) {
mmu_flags |= ARCH_MMU_FLAG_PERM_EXECUTE;
}

if (level > 0) {
switch (flags & X86_MMU_LARGE_PAT_MASK) {
Expand Down Expand Up @@ -392,18 +393,32 @@ X86PageTableBase::PtFlags X86PageTableEpt::intermediate_flags() {

X86PageTableBase::PtFlags X86PageTableEpt::terminal_flags(PageTableLevel level,
uint flags) {
DEBUG_ASSERT((flags & ARCH_MMU_FLAG_CACHE_MASK) == ARCH_MMU_FLAG_CACHED);
// Only the write-back memory type is supported.
X86PageTableBase::PtFlags terminal_flags = X86_EPT_WB;
X86PageTableBase::PtFlags terminal_flags = 0;

if (flags & ARCH_MMU_FLAG_PERM_READ)
if (flags & ARCH_MMU_FLAG_PERM_READ) {
terminal_flags |= X86_EPT_R;

if (flags & ARCH_MMU_FLAG_PERM_WRITE)
}
if (flags & ARCH_MMU_FLAG_PERM_WRITE) {
terminal_flags |= X86_EPT_W;

if (flags & ARCH_MMU_FLAG_PERM_EXECUTE)
}
if (flags & ARCH_MMU_FLAG_PERM_EXECUTE) {
terminal_flags |= X86_EPT_X;
}

switch (flags & ARCH_MMU_FLAG_CACHE_MASK) {
case ARCH_MMU_FLAG_CACHED:
terminal_flags |= X86_EPT_WB;
break;
case ARCH_MMU_FLAG_UNCACHED_DEVICE:
case ARCH_MMU_FLAG_UNCACHED:
terminal_flags |= X86_EPT_UC;
break;
case ARCH_MMU_FLAG_WRITE_COMBINING:
terminal_flags |= X86_EPT_WC;
break;
default:
PANIC_UNIMPLEMENTED;
}

return terminal_flags;
}
Expand All @@ -422,17 +437,31 @@ void X86PageTableEpt::TlbInvalidate(PendingTlbInvalidation* pending) {
}

uint X86PageTableEpt::pt_flags_to_mmu_flags(PtFlags flags, PageTableLevel level) {
// Only the write-back memory type is supported.
uint mmu_flags = ARCH_MMU_FLAG_CACHED;
uint mmu_flags = 0;

if (flags & X86_EPT_R)
if (flags & X86_EPT_R) {
mmu_flags |= ARCH_MMU_FLAG_PERM_READ;

if (flags & X86_EPT_W)
}
if (flags & X86_EPT_W) {
mmu_flags |= ARCH_MMU_FLAG_PERM_WRITE;

if (flags & X86_EPT_X)
}
if (flags & X86_EPT_X) {
mmu_flags |= ARCH_MMU_FLAG_PERM_EXECUTE;
}

switch (flags & X86_EPT_MEMORY_TYPE_MASK) {
case X86_EPT_WB:
mmu_flags |= ARCH_MMU_FLAG_CACHED;
break;
case X86_EPT_UC:
mmu_flags |= ARCH_MMU_FLAG_UNCACHED;
break;
case X86_EPT_WC:
mmu_flags |= ARCH_MMU_FLAG_WRITE_COMBINING;
break;
default:
PANIC_UNIMPLEMENTED;
}

return mmu_flags;
}
Expand Down
Loading

0 comments on commit ffd5fb5

Please sign in to comment.