mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-07 13:43:51 +00:00
KVM: arm64: nv: Add fine grained trap forwarding infrastructure
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@redhat.com> Signed-off-by: Marc Zyngier <maz@kernel.org> Reviewed-by: Jing Zhang <jingzhangos@google.com> Link: https://lore.kernel.org/r/20230815183903.2735724-20-maz@kernel.org
This commit is contained in:
parent
e880bd3363
commit
15b4d82d69
@ -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) ||
|
||||
|
Loading…
Reference in New Issue
Block a user