mirror of
https://github.com/torvalds/linux.git
synced 2026-05-31 18:43:33 +02:00
KVM: arm64: Enforce absence of FEAT_FGT on FGT registers
As we want to enforce FGT registers behaving as RES0 when FEAT_FGT is not exposed to the guest, We move a bumch of things that are so far passed as parameter into a structure that points to the bit description. Reviewed-by: Oliver Upton <oliver.upton@linux.dev> Signed-off-by: Marc Zyngier <maz@kernel.org>
This commit is contained in:
parent
559442afea
commit
7d3a4d0489
|
|
@ -458,6 +458,10 @@ static const struct reg_bits_to_feat_map hfgrtr_feat_map[] = {
|
|||
NEVER_FGU, FEAT_AA64EL1),
|
||||
};
|
||||
|
||||
|
||||
static const DECLARE_FEAT_MAP_FGT(hfgrtr_desc, hfgrtr_masks,
|
||||
hfgrtr_feat_map, FEAT_FGT);
|
||||
|
||||
static const struct reg_bits_to_feat_map hfgwtr_feat_map[] = {
|
||||
NEEDS_FEAT(HFGWTR_EL2_nAMAIR2_EL1 |
|
||||
HFGWTR_EL2_nMAIR2_EL1,
|
||||
|
|
@ -522,6 +526,9 @@ static const struct reg_bits_to_feat_map hfgwtr_feat_map[] = {
|
|||
NEVER_FGU, FEAT_AA64EL1),
|
||||
};
|
||||
|
||||
static const DECLARE_FEAT_MAP_FGT(hfgwtr_desc, hfgwtr_masks,
|
||||
hfgwtr_feat_map, FEAT_FGT);
|
||||
|
||||
static const struct reg_bits_to_feat_map hdfgrtr_feat_map[] = {
|
||||
NEEDS_FEAT(HDFGRTR_EL2_PMBIDR_EL1 |
|
||||
HDFGRTR_EL2_PMSLATFR_EL1 |
|
||||
|
|
@ -589,6 +596,9 @@ static const struct reg_bits_to_feat_map hdfgrtr_feat_map[] = {
|
|||
NEVER_FGU, FEAT_AA64EL1)
|
||||
};
|
||||
|
||||
static const DECLARE_FEAT_MAP_FGT(hdfgrtr_desc, hdfgrtr_masks,
|
||||
hdfgrtr_feat_map, FEAT_FGT);
|
||||
|
||||
static const struct reg_bits_to_feat_map hdfgwtr_feat_map[] = {
|
||||
NEEDS_FEAT(HDFGWTR_EL2_PMSLATFR_EL1 |
|
||||
HDFGWTR_EL2_PMSIRR_EL1 |
|
||||
|
|
@ -649,6 +659,8 @@ static const struct reg_bits_to_feat_map hdfgwtr_feat_map[] = {
|
|||
NEEDS_FEAT(HDFGWTR_EL2_TRFCR_EL1, FEAT_TRF),
|
||||
};
|
||||
|
||||
static const DECLARE_FEAT_MAP_FGT(hdfgwtr_desc, hdfgwtr_masks,
|
||||
hdfgwtr_feat_map, FEAT_FGT);
|
||||
|
||||
static const struct reg_bits_to_feat_map hfgitr_feat_map[] = {
|
||||
NEEDS_FEAT(HFGITR_EL2_PSBCSYNC, FEAT_SPEv1p5),
|
||||
|
|
@ -723,6 +735,9 @@ static const struct reg_bits_to_feat_map hfgitr_feat_map[] = {
|
|||
NEVER_FGU, FEAT_AA64EL1),
|
||||
};
|
||||
|
||||
static const DECLARE_FEAT_MAP_FGT(hfgitr_desc, hfgitr_masks,
|
||||
hfgitr_feat_map, FEAT_FGT);
|
||||
|
||||
static const struct reg_bits_to_feat_map hafgrtr_feat_map[] = {
|
||||
NEEDS_FEAT(HAFGRTR_EL2_AMEVTYPER115_EL0 |
|
||||
HAFGRTR_EL2_AMEVTYPER114_EL0 |
|
||||
|
|
@ -765,6 +780,9 @@ static const struct reg_bits_to_feat_map hafgrtr_feat_map[] = {
|
|||
FEAT_AMUv1),
|
||||
};
|
||||
|
||||
static const DECLARE_FEAT_MAP_FGT(hafgrtr_desc, hafgrtr_masks,
|
||||
hafgrtr_feat_map, FEAT_FGT);
|
||||
|
||||
static const struct reg_bits_to_feat_map hfgitr2_feat_map[] = {
|
||||
NEEDS_FEAT(HFGITR2_EL2_nDCCIVAPS, FEAT_PoPS),
|
||||
NEEDS_FEAT(HFGITR2_EL2_TSBCSYNC, FEAT_TRBEv1p1)
|
||||
|
|
@ -1122,20 +1140,25 @@ static void __init check_feat_map(const struct reg_bits_to_feat_map *map,
|
|||
str, mask ^ ~res0);
|
||||
}
|
||||
|
||||
static u64 reg_feat_map_bits(const struct reg_bits_to_feat_map *map)
|
||||
{
|
||||
return map->flags & RES0_POINTER ? ~(*map->res0p) : map->bits;
|
||||
}
|
||||
|
||||
static void __init check_reg_desc(const struct reg_feat_map_desc *r)
|
||||
{
|
||||
check_feat_map(r->bit_feat_map, r->bit_feat_map_sz,
|
||||
~reg_feat_map_bits(&r->feat_map), r->name);
|
||||
}
|
||||
|
||||
void __init check_feature_map(void)
|
||||
{
|
||||
check_feat_map(hfgrtr_feat_map, ARRAY_SIZE(hfgrtr_feat_map),
|
||||
hfgrtr_masks.res0, hfgrtr_masks.str);
|
||||
check_feat_map(hfgwtr_feat_map, ARRAY_SIZE(hfgwtr_feat_map),
|
||||
hfgwtr_masks.res0, hfgwtr_masks.str);
|
||||
check_feat_map(hfgitr_feat_map, ARRAY_SIZE(hfgitr_feat_map),
|
||||
hfgitr_masks.res0, hfgitr_masks.str);
|
||||
check_feat_map(hdfgrtr_feat_map, ARRAY_SIZE(hdfgrtr_feat_map),
|
||||
hdfgrtr_masks.res0, hdfgrtr_masks.str);
|
||||
check_feat_map(hdfgwtr_feat_map, ARRAY_SIZE(hdfgwtr_feat_map),
|
||||
hdfgwtr_masks.res0, hdfgwtr_masks.str);
|
||||
check_feat_map(hafgrtr_feat_map, ARRAY_SIZE(hafgrtr_feat_map),
|
||||
hafgrtr_masks.res0, hafgrtr_masks.str);
|
||||
check_reg_desc(&hfgrtr_desc);
|
||||
check_reg_desc(&hfgwtr_desc);
|
||||
check_reg_desc(&hfgitr_desc);
|
||||
check_reg_desc(&hdfgrtr_desc);
|
||||
check_reg_desc(&hdfgwtr_desc);
|
||||
check_reg_desc(&hafgrtr_desc);
|
||||
check_feat_map(hcrx_feat_map, ARRAY_SIZE(hcrx_feat_map),
|
||||
__HCRX_EL2_RES0, "HCRX_EL2");
|
||||
check_feat_map(hcr_feat_map, ARRAY_SIZE(hcr_feat_map),
|
||||
|
|
@ -1190,7 +1213,7 @@ static u64 __compute_fixed_bits(struct kvm *kvm,
|
|||
match = idreg_feat_match(kvm, &map[i]);
|
||||
|
||||
if (!match || (map[i].flags & FIXED_VALUE))
|
||||
val |= map[i].bits;
|
||||
val |= reg_feat_map_bits(&map[i]);
|
||||
}
|
||||
|
||||
return val;
|
||||
|
|
@ -1206,6 +1229,29 @@ static u64 compute_res0_bits(struct kvm *kvm,
|
|||
require, exclude | FIXED_VALUE);
|
||||
}
|
||||
|
||||
static u64 compute_reg_res0_bits(struct kvm *kvm,
|
||||
const struct reg_feat_map_desc *r,
|
||||
unsigned long require, unsigned long exclude)
|
||||
|
||||
{
|
||||
u64 res0;
|
||||
|
||||
res0 = compute_res0_bits(kvm, r->bit_feat_map, r->bit_feat_map_sz,
|
||||
require, exclude);
|
||||
|
||||
/*
|
||||
* If computing FGUs, don't take RES0 or register existence
|
||||
* into account -- we're not computing bits for the register
|
||||
* itself.
|
||||
*/
|
||||
if (!(exclude & NEVER_FGU)) {
|
||||
res0 |= compute_res0_bits(kvm, &r->feat_map, 1, require, exclude);
|
||||
res0 |= ~reg_feat_map_bits(&r->feat_map);
|
||||
}
|
||||
|
||||
return res0;
|
||||
}
|
||||
|
||||
static u64 compute_fixed_bits(struct kvm *kvm,
|
||||
const struct reg_bits_to_feat_map *map,
|
||||
int map_size,
|
||||
|
|
@ -1223,30 +1269,24 @@ void compute_fgu(struct kvm *kvm, enum fgt_group_id fgt)
|
|||
|
||||
switch (fgt) {
|
||||
case HFGRTR_GROUP:
|
||||
val |= compute_res0_bits(kvm, hfgrtr_feat_map,
|
||||
ARRAY_SIZE(hfgrtr_feat_map),
|
||||
0, NEVER_FGU);
|
||||
val |= compute_res0_bits(kvm, hfgwtr_feat_map,
|
||||
ARRAY_SIZE(hfgwtr_feat_map),
|
||||
0, NEVER_FGU);
|
||||
val |= compute_reg_res0_bits(kvm, &hfgrtr_desc,
|
||||
0, NEVER_FGU);
|
||||
val |= compute_reg_res0_bits(kvm, &hfgwtr_desc,
|
||||
0, NEVER_FGU);
|
||||
break;
|
||||
case HFGITR_GROUP:
|
||||
val |= compute_res0_bits(kvm, hfgitr_feat_map,
|
||||
ARRAY_SIZE(hfgitr_feat_map),
|
||||
0, NEVER_FGU);
|
||||
val |= compute_reg_res0_bits(kvm, &hfgitr_desc,
|
||||
0, NEVER_FGU);
|
||||
break;
|
||||
case HDFGRTR_GROUP:
|
||||
val |= compute_res0_bits(kvm, hdfgrtr_feat_map,
|
||||
ARRAY_SIZE(hdfgrtr_feat_map),
|
||||
0, NEVER_FGU);
|
||||
val |= compute_res0_bits(kvm, hdfgwtr_feat_map,
|
||||
ARRAY_SIZE(hdfgwtr_feat_map),
|
||||
0, NEVER_FGU);
|
||||
val |= compute_reg_res0_bits(kvm, &hdfgrtr_desc,
|
||||
0, NEVER_FGU);
|
||||
val |= compute_reg_res0_bits(kvm, &hdfgwtr_desc,
|
||||
0, NEVER_FGU);
|
||||
break;
|
||||
case HAFGRTR_GROUP:
|
||||
val |= compute_res0_bits(kvm, hafgrtr_feat_map,
|
||||
ARRAY_SIZE(hafgrtr_feat_map),
|
||||
0, NEVER_FGU);
|
||||
val |= compute_reg_res0_bits(kvm, &hafgrtr_desc,
|
||||
0, NEVER_FGU);
|
||||
break;
|
||||
case HFGRTR2_GROUP:
|
||||
val |= compute_res0_bits(kvm, hfgrtr2_feat_map,
|
||||
|
|
@ -1282,39 +1322,27 @@ void get_reg_fixed_bits(struct kvm *kvm, enum vcpu_sysreg reg, u64 *res0, u64 *r
|
|||
|
||||
switch (reg) {
|
||||
case HFGRTR_EL2:
|
||||
*res0 = compute_res0_bits(kvm, hfgrtr_feat_map,
|
||||
ARRAY_SIZE(hfgrtr_feat_map), 0, 0);
|
||||
*res0 |= hfgrtr_masks.res0;
|
||||
*res0 = compute_reg_res0_bits(kvm, &hfgrtr_desc, 0, 0);
|
||||
*res1 = HFGRTR_EL2_RES1;
|
||||
break;
|
||||
case HFGWTR_EL2:
|
||||
*res0 = compute_res0_bits(kvm, hfgwtr_feat_map,
|
||||
ARRAY_SIZE(hfgwtr_feat_map), 0, 0);
|
||||
*res0 |= hfgwtr_masks.res0;
|
||||
*res0 = compute_reg_res0_bits(kvm, &hfgwtr_desc, 0, 0);
|
||||
*res1 = HFGWTR_EL2_RES1;
|
||||
break;
|
||||
case HFGITR_EL2:
|
||||
*res0 = compute_res0_bits(kvm, hfgitr_feat_map,
|
||||
ARRAY_SIZE(hfgitr_feat_map), 0, 0);
|
||||
*res0 |= hfgitr_masks.res0;
|
||||
*res0 = compute_reg_res0_bits(kvm, &hfgitr_desc, 0, 0);
|
||||
*res1 = HFGITR_EL2_RES1;
|
||||
break;
|
||||
case HDFGRTR_EL2:
|
||||
*res0 = compute_res0_bits(kvm, hdfgrtr_feat_map,
|
||||
ARRAY_SIZE(hdfgrtr_feat_map), 0, 0);
|
||||
*res0 |= hdfgrtr_masks.res0;
|
||||
*res0 = compute_reg_res0_bits(kvm, &hdfgrtr_desc, 0, 0);
|
||||
*res1 = HDFGRTR_EL2_RES1;
|
||||
break;
|
||||
case HDFGWTR_EL2:
|
||||
*res0 = compute_res0_bits(kvm, hdfgwtr_feat_map,
|
||||
ARRAY_SIZE(hdfgwtr_feat_map), 0, 0);
|
||||
*res0 |= hdfgwtr_masks.res0;
|
||||
*res0 = compute_reg_res0_bits(kvm, &hdfgwtr_desc, 0, 0);
|
||||
*res1 = HDFGWTR_EL2_RES1;
|
||||
break;
|
||||
case HAFGRTR_EL2:
|
||||
*res0 = compute_res0_bits(kvm, hafgrtr_feat_map,
|
||||
ARRAY_SIZE(hafgrtr_feat_map), 0, 0);
|
||||
*res0 |= hafgrtr_masks.res0;
|
||||
*res0 = compute_reg_res0_bits(kvm, &hafgrtr_desc, 0, 0);
|
||||
*res1 = HAFGRTR_EL2_RES1;
|
||||
break;
|
||||
case HFGRTR2_EL2:
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user