ANDROID: KVM: arm64: Add support for non-cacheable mappings

Hypervisor vendor modules may need to create non-cacheable mappings in
the hypervisor stage-1 for interacting with devices such as IOMMUs.

Add support for this memory type to the KVM pgtable API and implement
it for both stage-1 and stage-2.

Bug: 244373730
Signed-off-by: Will Deacon <willdeacon@google.com>
Change-Id: I2f88db7fe47e16366018e3e48f30d09b299ae6e4
This commit is contained in:
Will Deacon
2022-12-13 21:19:25 +00:00
parent e38c4149ed
commit 72cc19df8b
3 changed files with 31 additions and 7 deletions

View File

@@ -184,6 +184,7 @@ enum kvm_pgtable_stage2_flags {
* @KVM_PGTABLE_PROT_W: Write permission.
* @KVM_PGTABLE_PROT_R: Read permission.
* @KVM_PGTABLE_PROT_DEVICE: Device attributes.
* @KVM_PGTABLE_PROT_NC: Normal non-cacheable attributes.
* @KVM_PGTABLE_PROT_SW0: Software bit 0.
* @KVM_PGTABLE_PROT_SW1: Software bit 1.
* @KVM_PGTABLE_PROT_SW2: Software bit 2.
@@ -195,6 +196,7 @@ enum kvm_pgtable_prot {
KVM_PGTABLE_PROT_R = BIT(2),
KVM_PGTABLE_PROT_DEVICE = BIT(3),
KVM_PGTABLE_PROT_NC = BIT(4),
KVM_PGTABLE_PROT_SW0 = BIT(55),
KVM_PGTABLE_PROT_SW1 = BIT(56),

View File

@@ -147,6 +147,7 @@
* Memory types for Stage-2 translation
*/
#define MT_S2_NORMAL 0xf
#define MT_S2_NORMAL_NC 0x5
#define MT_S2_DEVICE_nGnRE 0x1
/*
@@ -154,6 +155,7 @@
* Stage-2 enforces Normal-WB and Device-nGnRE
*/
#define MT_S2_FWB_NORMAL 6
#define MT_S2_FWB_NORMAL_NC 5
#define MT_S2_FWB_DEVICE_nGnRE 1
#ifdef CONFIG_ARM64_4K_PAGES

View File

@@ -273,16 +273,26 @@ struct hyp_map_data {
static int hyp_set_prot_attr(enum kvm_pgtable_prot prot, kvm_pte_t *ptep)
{
bool device = prot & KVM_PGTABLE_PROT_DEVICE;
u32 mtype = device ? MT_DEVICE_nGnRE : MT_NORMAL;
kvm_pte_t attr = FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S1_ATTRIDX, mtype);
u32 sh = KVM_PTE_LEAF_ATTR_LO_S1_SH_IS;
u32 ap = (prot & KVM_PGTABLE_PROT_W) ? KVM_PTE_LEAF_ATTR_LO_S1_AP_RW :
KVM_PTE_LEAF_ATTR_LO_S1_AP_RO;
bool device = prot & KVM_PGTABLE_PROT_DEVICE;
u32 sh = KVM_PTE_LEAF_ATTR_LO_S1_SH_IS;
bool nc = prot & KVM_PGTABLE_PROT_NC;
kvm_pte_t attr;
u32 mtype;
if (!(prot & KVM_PGTABLE_PROT_R))
if (!(prot & KVM_PGTABLE_PROT_R) || (device && nc))
return -EINVAL;
if (device)
mtype = MT_DEVICE_nGnRnE;
else if (nc)
mtype = MT_NORMAL_NC;
else
mtype = MT_NORMAL;
attr = FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S1_ATTRIDX, mtype);
if (prot & KVM_PGTABLE_PROT_X) {
if (prot & KVM_PGTABLE_PROT_W)
return -EINVAL;
@@ -563,9 +573,19 @@ static int stage2_set_prot_attr(struct kvm_pgtable *pgt, enum kvm_pgtable_prot p
kvm_pte_t *ptep)
{
bool device = prot & KVM_PGTABLE_PROT_DEVICE;
kvm_pte_t attr = device ? KVM_S2_MEMATTR(pgt, DEVICE_nGnRE) :
KVM_S2_MEMATTR(pgt, NORMAL);
u32 sh = KVM_PTE_LEAF_ATTR_LO_S2_SH_IS;
bool nc = prot & KVM_PGTABLE_PROT_NC;
kvm_pte_t attr;
if (device && nc)
return -EINVAL;
if (device)
attr = KVM_S2_MEMATTR(pgt, DEVICE_nGnRE);
else if (nc)
attr = KVM_S2_MEMATTR(pgt, NORMAL_NC);
else
attr = KVM_S2_MEMATTR(pgt, NORMAL);
if (!(prot & KVM_PGTABLE_PROT_X))
attr |= KVM_PTE_LEAF_ATTR_HI_S2_XN;