Hi Marc, On Tue, Aug 15, 2023 at 11:47 AM Marc Zyngier <maz@xxxxxxxxxx> wrote: > > Fine Grained Traps are fun. Not. > > Implement the fine grained trap forwarding, reusing the Coarse Grained > Traps infrastructure previously implemented. > > Each sysreg/instruction inserted in the xarray gets a FGT group > (vaguely equivalent to a register number), a bit number in that register, > and a polarity. > > It is then pretty easy to check the FGT state at handling time, just > like we do for the coarse version (it is just faster). > > Reviewed-by: Eric Auger <eric.auger@xxxxxxxxxx> > Signed-off-by: Marc Zyngier <maz@xxxxxxxxxx> > --- > arch/arm64/kvm/emulate-nested.c | 90 +++++++++++++++++++++++++++++++-- > 1 file changed, 87 insertions(+), 3 deletions(-) > > diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c > index 860910386b5b..0da9d92ed921 100644 > --- a/arch/arm64/kvm/emulate-nested.c > +++ b/arch/arm64/kvm/emulate-nested.c > @@ -423,16 +423,23 @@ static const complex_condition_check ccc[] = { > * following layout for each trapped sysreg: > * > * [9:0] enum cgt_group_id (10 bits) > - * [62:10] Unused (53 bits) > + * [13:10] enum fgt_group_id (4 bits) > + * [19:14] bit number in the FGT register (6 bits) > + * [20] trap polarity (1 bit) > + * [62:21] Unused (42 bits) > * [63] RES0 - Must be zero, as lost on insertion in the xarray > */ > #define TC_CGT_BITS 10 > +#define TC_FGT_BITS 4 > > union trap_config { > u64 val; > struct { > unsigned long cgt:TC_CGT_BITS; /* Coarse Grained Trap id */ > - unsigned long unused:53; /* Unused, should be zero */ > + unsigned long fgt:TC_FGT_BITS; /* Fine Grained Trap id */ > + unsigned long bit:6; /* Bit number */ > + unsigned long pol:1; /* Polarity */ > + unsigned long unused:42; /* Unused, should be zero */ > unsigned long mbz:1; /* Must Be Zero */ > }; > }; > @@ -929,6 +936,28 @@ static const struct encoding_to_trap_config encoding_to_cgt[] __initconst = { > > static DEFINE_XARRAY(sr_forward_xa); > > +enum fgt_group_id { > + __NO_FGT_GROUP__, > + > + /* Must be last */ > + __NR_FGT_GROUP_IDS__ > +}; > + > +#define SR_FGT(sr, g, b, p) \ > + { \ > + .encoding = sr, \ > + .end = sr, \ > + .tc = { \ > + .fgt = g ## _GROUP, \ > + .bit = g ## _EL2_ ## b ## _SHIFT, \ > + .pol = p, \ > + }, \ > + .line = __LINE__, \ > + } > + > +static const struct encoding_to_trap_config encoding_to_fgt[] __initconst = { > +}; > + > static union trap_config get_trap_config(u32 sysreg) > { > return (union trap_config) { > @@ -957,6 +986,7 @@ int __init populate_nv_trap_config(void) > > BUILD_BUG_ON(sizeof(union trap_config) != sizeof(void *)); > BUILD_BUG_ON(__NR_CGT_GROUP_IDS__ > BIT(TC_CGT_BITS)); > + BUILD_BUG_ON(__NR_FGT_GROUP_IDS__ > BIT(TC_FGT_BITS)); > > for (int i = 0; i < ARRAY_SIZE(encoding_to_cgt); i++) { > const struct encoding_to_trap_config *cgt = &encoding_to_cgt[i]; > @@ -990,6 +1020,34 @@ int __init populate_nv_trap_config(void) > kvm_info("nv: %ld coarse grained trap handlers\n", > ARRAY_SIZE(encoding_to_cgt)); > > + if (!cpus_have_final_cap(ARM64_HAS_FGT)) > + goto check_mcb; > + > + for (int i = 0; i < ARRAY_SIZE(encoding_to_fgt); i++) { > + const struct encoding_to_trap_config *fgt = &encoding_to_fgt[i]; > + union trap_config tc; > + > + if (fgt->tc.fgt >= __NR_FGT_GROUP_IDS__) { > + ret = -EINVAL; > + print_nv_trap_error(fgt, "Invalid FGT", ret); > + } > + > + tc = get_trap_config(fgt->encoding); > + > + if (tc.fgt) { > + ret = -EINVAL; > + print_nv_trap_error(fgt, "Duplicate FGT", ret); > + } > + > + tc.val |= fgt->tc.val; > + xa_store(&sr_forward_xa, fgt->encoding, > + xa_mk_value(tc.val), GFP_KERNEL); > + } > + > + kvm_info("nv: %ld fine grained trap handlers\n", > + ARRAY_SIZE(encoding_to_fgt)); > + > +check_mcb: > for (int id = __MULTIPLE_CONTROL_BITS__; id < __COMPLEX_CONDITIONS__; id++) { > const enum cgt_group_id *cgids; > > @@ -1056,13 +1114,26 @@ static enum trap_behaviour compute_trap_behaviour(struct kvm_vcpu *vcpu, > return __compute_trap_behaviour(vcpu, tc.cgt, b); > } > > +static bool check_fgt_bit(u64 val, const union trap_config tc) > +{ > + return ((val >> tc.bit) & 1) == tc.pol; > +} > + > +#define sanitised_sys_reg(vcpu, reg) \ > + ({ \ > + u64 __val; \ > + __val = __vcpu_sys_reg(vcpu, reg); \ > + __val &= ~__ ## reg ## _RES0; \ > + (__val); \ > + }) > + > bool __check_nv_sr_forward(struct kvm_vcpu *vcpu) > { > union trap_config tc; > enum trap_behaviour b; > bool is_read; > u32 sysreg; > - u64 esr; > + u64 esr, val; > > if (!vcpu_has_nv(vcpu) || is_hyp_ctxt(vcpu)) > return false; > @@ -1085,6 +1156,19 @@ bool __check_nv_sr_forward(struct kvm_vcpu *vcpu) > if (!tc.val) > return false; > > + switch ((enum fgt_group_id)tc.fgt) { > + case __NO_FGT_GROUP__: > + break; > + > + case __NR_FGT_GROUP_IDS__: > + /* Something is really wrong, bail out */ > + WARN_ONCE(1, "__NR_FGT_GROUP_IDS__"); > + return false; > + } > + > + if (tc.fgt != __NO_FGT_GROUP__ && check_fgt_bit(val, tc)) > + goto inject; > + > b = compute_trap_behaviour(vcpu, tc); > > if (((b & BEHAVE_FORWARD_READ) && is_read) || > -- > 2.34.1 > Reviewed-by: Jing Zhang <jingzhangos@xxxxxxxxxx> Jing