Skip to content

Commit e39ce70

Browse files
Marc Zyngieroupton
authored andcommitted
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 <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Oliver Upton <[email protected]>
1 parent 7cd5c27 commit e39ce70

File tree

1 file changed

+53
-0
lines changed

1 file changed

+53
-0
lines changed

arch/arm64/kvm/at.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,11 @@ struct s1_walk_result {
4040
u8 APTable;
4141
bool UXNTable;
4242
bool PXNTable;
43+
bool uov;
4344
bool ur;
4445
bool uw;
4546
bool ux;
47+
bool pov;
4648
bool pr;
4749
bool pw;
4850
bool px;
@@ -881,6 +883,9 @@ static void compute_s1_direct_permissions(struct kvm_vcpu *vcpu,
881883
/* XN maps to UXN */
882884
wr->px = !(wr->desc & PTE_UXN);
883885
}
886+
887+
wr->pov = wi->poe;
888+
wr->uov = wi->e0poe;
884889
}
885890

886891
static void compute_s1_hierarchical_permissions(struct kvm_vcpu *vcpu,
@@ -1016,13 +1021,58 @@ static void compute_s1_indirect_permissions(struct kvm_vcpu *vcpu,
10161021
else
10171022
set_unpriv_perms(wr, false, false, false);
10181023

1024+
wr->pov = wi->poe && !(pp & BIT(3));
1025+
wr->uov = wi->e0poe && !(up & BIT(3));
1026+
10191027
/* R_VFPJF */
10201028
if (wr->px && wr->uw) {
10211029
set_priv_perms(wr, false, false, false);
10221030
set_unpriv_perms(wr, false, false, false);
10231031
}
10241032
}
10251033

1034+
static void compute_s1_overlay_permissions(struct kvm_vcpu *vcpu,
1035+
struct s1_walk_info *wi,
1036+
struct s1_walk_result *wr)
1037+
{
1038+
u8 idx, pov_perms, uov_perms;
1039+
1040+
idx = FIELD_GET(PTE_PO_IDX_MASK, wr->desc);
1041+
1042+
switch (wi->regime) {
1043+
case TR_EL10:
1044+
pov_perms = perm_idx(vcpu, POR_EL1, idx);
1045+
uov_perms = perm_idx(vcpu, POR_EL0, idx);
1046+
break;
1047+
case TR_EL20:
1048+
pov_perms = perm_idx(vcpu, POR_EL2, idx);
1049+
uov_perms = perm_idx(vcpu, POR_EL0, idx);
1050+
break;
1051+
case TR_EL2:
1052+
pov_perms = perm_idx(vcpu, POR_EL2, idx);
1053+
uov_perms = 0;
1054+
break;
1055+
}
1056+
1057+
if (pov_perms & ~POE_RXW)
1058+
pov_perms = POE_NONE;
1059+
1060+
if (wi->poe && wr->pov) {
1061+
wr->pr &= pov_perms & POE_R;
1062+
wr->px &= pov_perms & POE_X;
1063+
wr->pw &= pov_perms & POE_W;
1064+
}
1065+
1066+
if (uov_perms & ~POE_RXW)
1067+
uov_perms = POE_NONE;
1068+
1069+
if (wi->e0poe && wr->uov) {
1070+
wr->ur &= uov_perms & POE_R;
1071+
wr->ux &= uov_perms & POE_X;
1072+
wr->uw &= uov_perms & POE_W;
1073+
}
1074+
}
1075+
10261076
static void compute_s1_permissions(struct kvm_vcpu *vcpu,
10271077
struct s1_walk_info *wi,
10281078
struct s1_walk_result *wr)
@@ -1037,6 +1087,9 @@ static void compute_s1_permissions(struct kvm_vcpu *vcpu,
10371087
if (!wi->hpd)
10381088
compute_s1_hierarchical_permissions(vcpu, wi, wr);
10391089

1090+
if (wi->poe || wi->e0poe)
1091+
compute_s1_overlay_permissions(vcpu, wi, wr);
1092+
10401093
pan = wi->pan && (wr->ur || wr->uw ||
10411094
(pan3_enabled(vcpu, wi->regime) && wr->ux));
10421095
wr->pw &= !pan;

0 commit comments

Comments
 (0)