ANDROID: KVM: arm64: Allow setting {P,U}XN in stage-2 PTEs
FEAT_XNX allows to specify PXN and UXN attributes on stage-2 entries. Make this usable from pKVM by exposing two new kvm_pgtable_prot entries for each of them. No functional changes intended. Bug: 264070847 Change-Id: I47d861fa64ba511370b182f4609fe1c27695a949 Signed-off-by: Quentin Perret <qperret@google.com>
This commit is contained in:
parent
b7aff5c603
commit
b489c53001
3 changed files with 53 additions and 15 deletions
|
|
@ -72,7 +72,10 @@ typedef u64 kvm_pte_t;
|
|||
|
||||
#define KVM_PTE_LEAF_ATTR_HI_S1_XN BIT(54)
|
||||
|
||||
#define KVM_PTE_LEAF_ATTR_HI_S2_XN BIT(54)
|
||||
#define KVM_PTE_LEAF_ATTR_HI_S2_XN_PXN 1
|
||||
#define KVM_PTE_LEAF_ATTR_HI_S2_XN_UXN 3
|
||||
#define KVM_PTE_LEAF_ATTR_HI_S2_XN_XN 2
|
||||
#define KVM_PTE_LEAF_ATTR_HI_S2_XN GENMASK(54, 53)
|
||||
|
||||
static inline bool kvm_pte_valid(kvm_pte_t pte)
|
||||
{
|
||||
|
|
@ -189,7 +192,9 @@ 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_NC: Normal non-cacheable attributes.
|
||||
* @KVM_PGTABLE_PROT_PXN: Privileged execute-never.
|
||||
* @KVM_PGTABLE_PROT_UXN: Unprivileged execute-never.
|
||||
* @KVM_PGTABLE_PROT_SW0: Software bit 0.
|
||||
* @KVM_PGTABLE_PROT_SW1: Software bit 1.
|
||||
* @KVM_PGTABLE_PROT_SW2: Software bit 2.
|
||||
|
|
@ -202,6 +207,8 @@ enum kvm_pgtable_prot {
|
|||
|
||||
KVM_PGTABLE_PROT_DEVICE = BIT(3),
|
||||
KVM_PGTABLE_PROT_NC = BIT(4),
|
||||
KVM_PGTABLE_PROT_PXN = BIT(5),
|
||||
KVM_PGTABLE_PROT_UXN = BIT(6),
|
||||
|
||||
KVM_PGTABLE_PROT_SW0 = BIT(55),
|
||||
KVM_PGTABLE_PROT_SW1 = BIT(56),
|
||||
|
|
|
|||
|
|
@ -2037,6 +2037,10 @@ static int restrict_host_page_perms(u64 addr, kvm_pte_t pte, u32 level, enum kvm
|
|||
return ret;
|
||||
}
|
||||
|
||||
#define MODULE_PROT_ALLOWLIST (KVM_PGTABLE_PROT_RWX | \
|
||||
KVM_PGTABLE_PROT_NC | \
|
||||
KVM_PGTABLE_PROT_PXN | \
|
||||
KVM_PGTABLE_PROT_UXN)
|
||||
int module_change_host_page_prot(u64 pfn, enum kvm_pgtable_prot prot)
|
||||
{
|
||||
u64 addr = hyp_pfn_to_phys(pfn);
|
||||
|
|
@ -2045,7 +2049,7 @@ int module_change_host_page_prot(u64 pfn, enum kvm_pgtable_prot prot)
|
|||
u32 level;
|
||||
int ret;
|
||||
|
||||
if ((prot & KVM_PGTABLE_PROT_RWX) != prot)
|
||||
if ((prot & MODULE_PROT_ALLOWLIST) != prot)
|
||||
return -EINVAL;
|
||||
|
||||
host_lock_component();
|
||||
|
|
|
|||
|
|
@ -276,7 +276,8 @@ static int hyp_set_prot_attr(enum kvm_pgtable_prot prot, kvm_pte_t *ptep)
|
|||
kvm_pte_t attr;
|
||||
u32 mtype;
|
||||
|
||||
if (!(prot & KVM_PGTABLE_PROT_R) || (device && nc))
|
||||
if (!(prot & KVM_PGTABLE_PROT_R) || (device && nc) ||
|
||||
(prot & (KVM_PGTABLE_PROT_PXN | KVM_PGTABLE_PROT_UXN)))
|
||||
return -EINVAL;
|
||||
|
||||
if (device)
|
||||
|
|
@ -565,16 +566,15 @@ static bool stage2_has_fwb(struct kvm_pgtable *pgt)
|
|||
#define KVM_S2_MEMATTR(pgt, attr) PAGE_S2_MEMATTR(attr, stage2_has_fwb(pgt))
|
||||
|
||||
static int stage2_set_prot_attr(struct kvm_pgtable *pgt, enum kvm_pgtable_prot prot,
|
||||
kvm_pte_t *ptep)
|
||||
kvm_pte_t *ptep)
|
||||
{
|
||||
u64 exec_type = KVM_PTE_LEAF_ATTR_HI_S2_XN_XN;
|
||||
bool device = prot & KVM_PGTABLE_PROT_DEVICE;
|
||||
u32 sh = KVM_PTE_LEAF_ATTR_LO_S2_SH_IS;
|
||||
bool nc = prot & KVM_PGTABLE_PROT_NC;
|
||||
enum kvm_pgtable_prot exec_prot;
|
||||
kvm_pte_t attr;
|
||||
|
||||
if (device && nc)
|
||||
return -EINVAL;
|
||||
|
||||
if (device)
|
||||
attr = KVM_S2_MEMATTR(pgt, DEVICE_nGnRE);
|
||||
else if (nc)
|
||||
|
|
@ -582,11 +582,23 @@ static int stage2_set_prot_attr(struct kvm_pgtable *pgt, enum kvm_pgtable_prot p
|
|||
else
|
||||
attr = KVM_S2_MEMATTR(pgt, NORMAL);
|
||||
|
||||
if (!(prot & KVM_PGTABLE_PROT_X))
|
||||
attr |= KVM_PTE_LEAF_ATTR_HI_S2_XN;
|
||||
else if (device)
|
||||
return -EINVAL;
|
||||
exec_prot = prot & (KVM_PGTABLE_PROT_X | KVM_PGTABLE_PROT_PXN | KVM_PGTABLE_PROT_UXN);
|
||||
switch(exec_prot) {
|
||||
case KVM_PGTABLE_PROT_X:
|
||||
goto set_ap;
|
||||
case KVM_PGTABLE_PROT_PXN:
|
||||
exec_type = KVM_PTE_LEAF_ATTR_HI_S2_XN_PXN;
|
||||
break;
|
||||
case KVM_PGTABLE_PROT_UXN:
|
||||
exec_type = KVM_PTE_LEAF_ATTR_HI_S2_XN_UXN;
|
||||
break;
|
||||
default:
|
||||
if (exec_prot)
|
||||
return -EINVAL;
|
||||
}
|
||||
attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_HI_S2_XN, exec_type);
|
||||
|
||||
set_ap:
|
||||
if (prot & KVM_PGTABLE_PROT_R)
|
||||
attr |= KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R;
|
||||
|
||||
|
|
@ -612,8 +624,21 @@ enum kvm_pgtable_prot kvm_pgtable_stage2_pte_prot(kvm_pte_t pte)
|
|||
prot |= KVM_PGTABLE_PROT_R;
|
||||
if (pte & KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W)
|
||||
prot |= KVM_PGTABLE_PROT_W;
|
||||
if (!(pte & KVM_PTE_LEAF_ATTR_HI_S2_XN))
|
||||
switch(FIELD_GET(KVM_PTE_LEAF_ATTR_HI_S2_XN, pte)) {
|
||||
case 0:
|
||||
prot |= KVM_PGTABLE_PROT_X;
|
||||
break;
|
||||
case KVM_PTE_LEAF_ATTR_HI_S2_XN_PXN:
|
||||
prot |= KVM_PGTABLE_PROT_PXN;
|
||||
break;
|
||||
case KVM_PTE_LEAF_ATTR_HI_S2_XN_UXN:
|
||||
prot |= KVM_PGTABLE_PROT_UXN;
|
||||
break;
|
||||
case KVM_PTE_LEAF_ATTR_HI_S2_XN_XN:
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
return prot;
|
||||
}
|
||||
|
|
@ -655,7 +680,9 @@ static bool stage2_pte_cacheable(struct kvm_pgtable *pgt, kvm_pte_t pte)
|
|||
|
||||
static bool stage2_pte_executable(kvm_pte_t pte)
|
||||
{
|
||||
return kvm_pte_valid(pte) && !(pte & KVM_PTE_LEAF_ATTR_HI_S2_XN);
|
||||
kvm_pte_t xn = FIELD_GET(KVM_PTE_LEAF_ATTR_HI_S2_XN, pte);
|
||||
|
||||
return kvm_pte_valid(pte) && xn != KVM_PTE_LEAF_ATTR_HI_S2_XN_XN;
|
||||
}
|
||||
|
||||
static bool stage2_leaf_mapping_allowed(u64 addr, u64 end, u32 level,
|
||||
|
|
@ -1154,7 +1181,7 @@ int kvm_pgtable_stage2_relax_perms(struct kvm_pgtable *pgt, u64 addr,
|
|||
u32 level;
|
||||
kvm_pte_t set = 0, clr = 0;
|
||||
|
||||
if (prot & KVM_PTE_LEAF_ATTR_HI_SW)
|
||||
if (prot & !KVM_PGTABLE_PROT_RWX)
|
||||
return -EINVAL;
|
||||
|
||||
if (prot & KVM_PGTABLE_PROT_R)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue