mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-06 05:06:29 +00:00
KVM: arm64: Handle stage-1 permission overlays
We now have the intrastructure in place to emulate S1POE: - direct permissions are always overlay-capable - indirect permissions are overlay-capable if the permissions are in the 0b0xxx range - the overlays are strictly substractive Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20241023145345.1613824-37-maz@kernel.org Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
This commit is contained in:
parent
7cd5c2796c
commit
e39ce7033c
@ -40,9 +40,11 @@ struct s1_walk_result {
|
||||
u8 APTable;
|
||||
bool UXNTable;
|
||||
bool PXNTable;
|
||||
bool uov;
|
||||
bool ur;
|
||||
bool uw;
|
||||
bool ux;
|
||||
bool pov;
|
||||
bool pr;
|
||||
bool pw;
|
||||
bool px;
|
||||
@ -881,6 +883,9 @@ static void compute_s1_direct_permissions(struct kvm_vcpu *vcpu,
|
||||
/* XN maps to UXN */
|
||||
wr->px = !(wr->desc & PTE_UXN);
|
||||
}
|
||||
|
||||
wr->pov = wi->poe;
|
||||
wr->uov = wi->e0poe;
|
||||
}
|
||||
|
||||
static void compute_s1_hierarchical_permissions(struct kvm_vcpu *vcpu,
|
||||
@ -1016,6 +1021,9 @@ static void compute_s1_indirect_permissions(struct kvm_vcpu *vcpu,
|
||||
else
|
||||
set_unpriv_perms(wr, false, false, false);
|
||||
|
||||
wr->pov = wi->poe && !(pp & BIT(3));
|
||||
wr->uov = wi->e0poe && !(up & BIT(3));
|
||||
|
||||
/* R_VFPJF */
|
||||
if (wr->px && wr->uw) {
|
||||
set_priv_perms(wr, false, false, false);
|
||||
@ -1023,6 +1031,48 @@ static void compute_s1_indirect_permissions(struct kvm_vcpu *vcpu,
|
||||
}
|
||||
}
|
||||
|
||||
static void compute_s1_overlay_permissions(struct kvm_vcpu *vcpu,
|
||||
struct s1_walk_info *wi,
|
||||
struct s1_walk_result *wr)
|
||||
{
|
||||
u8 idx, pov_perms, uov_perms;
|
||||
|
||||
idx = FIELD_GET(PTE_PO_IDX_MASK, wr->desc);
|
||||
|
||||
switch (wi->regime) {
|
||||
case TR_EL10:
|
||||
pov_perms = perm_idx(vcpu, POR_EL1, idx);
|
||||
uov_perms = perm_idx(vcpu, POR_EL0, idx);
|
||||
break;
|
||||
case TR_EL20:
|
||||
pov_perms = perm_idx(vcpu, POR_EL2, idx);
|
||||
uov_perms = perm_idx(vcpu, POR_EL0, idx);
|
||||
break;
|
||||
case TR_EL2:
|
||||
pov_perms = perm_idx(vcpu, POR_EL2, idx);
|
||||
uov_perms = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (pov_perms & ~POE_RXW)
|
||||
pov_perms = POE_NONE;
|
||||
|
||||
if (wi->poe && wr->pov) {
|
||||
wr->pr &= pov_perms & POE_R;
|
||||
wr->px &= pov_perms & POE_X;
|
||||
wr->pw &= pov_perms & POE_W;
|
||||
}
|
||||
|
||||
if (uov_perms & ~POE_RXW)
|
||||
uov_perms = POE_NONE;
|
||||
|
||||
if (wi->e0poe && wr->uov) {
|
||||
wr->ur &= uov_perms & POE_R;
|
||||
wr->ux &= uov_perms & POE_X;
|
||||
wr->uw &= uov_perms & POE_W;
|
||||
}
|
||||
}
|
||||
|
||||
static void compute_s1_permissions(struct kvm_vcpu *vcpu,
|
||||
struct s1_walk_info *wi,
|
||||
struct s1_walk_result *wr)
|
||||
@ -1037,6 +1087,9 @@ static void compute_s1_permissions(struct kvm_vcpu *vcpu,
|
||||
if (!wi->hpd)
|
||||
compute_s1_hierarchical_permissions(vcpu, wi, wr);
|
||||
|
||||
if (wi->poe || wi->e0poe)
|
||||
compute_s1_overlay_permissions(vcpu, wi, wr);
|
||||
|
||||
pan = wi->pan && (wr->ur || wr->uw ||
|
||||
(pan3_enabled(vcpu, wi->regime) && wr->ux));
|
||||
wr->pw &= !pan;
|
||||
|
Loading…
Reference in New Issue
Block a user