ANDROID: KVM: arm64: Allow 16 host_smc handlers
Allow pKVM modules to register up to 16 host_smc handlers. The SMC will be considered has handled on the first one returning True. Unhandled SMC will be forwarded. Bug: 357781595 Bug: 382397533 Change-Id: I58717927d7b47b8af5532ec2bfe57e022186e1d3 Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
This commit is contained in:
@@ -93,8 +93,11 @@ enum pkvm_psci_notification {
|
||||
* @host_stage2_get_leaf: Query the host's stage2 page-table entry for
|
||||
* the page @phys.
|
||||
* @register_host_smc_handler: @cb is called whenever the host issues an SMC
|
||||
* pKVM couldn't handle. If @cb returns false, the
|
||||
* SMC will be forwarded to EL3.
|
||||
* pKVM couldn't handle.
|
||||
* Up-to 16 handlers can be registered. The handler
|
||||
* order depends on the registration order. If no
|
||||
* handler return True, the SMC is forwarded to
|
||||
* EL3.
|
||||
* @register_default_trap_handler:
|
||||
* @cb is called whenever EL2 traps EL1 and pKVM
|
||||
* has not handled it. If @cb returns false, the
|
||||
|
||||
@@ -18,6 +18,7 @@ int __pkvm_register_hcall(unsigned long hfn_hyp_va);
|
||||
int handle_host_dynamic_hcall(struct user_pt_regs *regs, int id);
|
||||
void __pkvm_close_module_registration(void);
|
||||
bool module_handle_host_perm_fault(struct user_pt_regs *regs, u64 esr, u64 addr);
|
||||
bool module_handle_host_smc(struct user_pt_regs *regs);
|
||||
#else
|
||||
static inline int __pkvm_init_module(void *module_init) { return -EOPNOTSUPP; }
|
||||
static inline int
|
||||
@@ -29,4 +30,5 @@ handle_host_dynamic_hcall(struct kvm_cpu_context *host_ctxt, int id)
|
||||
}
|
||||
static inline void __pkvm_close_module_registration(void) { }
|
||||
bool module_handle_host_perm_fault(struct user_pt_regs *regs, u64 esr, u64 addr) { return false; }
|
||||
bool module_handle_host_smc(struct user_pt_regs *regs) { return false; }
|
||||
#endif
|
||||
|
||||
@@ -63,21 +63,10 @@ static inline void hyp_reqs_smccc_encode(unsigned long ret, struct kvm_cpu_conte
|
||||
|
||||
void __kvm_hyp_host_forward_smc(struct kvm_cpu_context *host_ctxt);
|
||||
|
||||
static bool (*default_host_smc_handler)(struct user_pt_regs *regs);
|
||||
static bool (*default_trap_handler)(struct user_pt_regs *regs);
|
||||
static bool (*unmask_serror)(void);
|
||||
static void (*mask_serror)(void);
|
||||
|
||||
int __pkvm_register_host_smc_handler(bool (*cb)(struct user_pt_regs *))
|
||||
{
|
||||
/*
|
||||
* Paired with smp_load_acquire(&default_host_smc_handler) in
|
||||
* handle_host_smc(). Ensure memory stores happening during a pKVM module
|
||||
* init are observed before executing the callback.
|
||||
*/
|
||||
return cmpxchg_release(&default_host_smc_handler, NULL, cb) ? -EBUSY : 0;
|
||||
}
|
||||
|
||||
int __pkvm_register_default_trap_handler(bool (*cb)(struct user_pt_regs *))
|
||||
{
|
||||
return cmpxchg(&default_trap_handler, NULL, cb) ? -EBUSY : 0;
|
||||
@@ -1856,8 +1845,8 @@ static void handle_host_smc(struct kvm_cpu_context *host_ctxt)
|
||||
handled = kvm_host_ffa_handler(host_ctxt, func_id);
|
||||
if (!handled)
|
||||
handled = kvm_host_scmi_handler(host_ctxt);
|
||||
if (!handled && smp_load_acquire(&default_host_smc_handler))
|
||||
handled = default_host_smc_handler(&host_ctxt->regs);
|
||||
if (!handled)
|
||||
handled = module_handle_host_smc(&host_ctxt->regs);
|
||||
if (!handled) {
|
||||
__hyp_exit();
|
||||
__kvm_hyp_host_forward_smc(host_ctxt);
|
||||
|
||||
@@ -132,6 +132,7 @@ static int __hyp_smp_processor_id(void)
|
||||
|
||||
enum mod_handler_type {
|
||||
HOST_FAULT_HANDLER = 0,
|
||||
HOST_SMC_HANDLER,
|
||||
NUM_MOD_HANDLER_TYPES,
|
||||
};
|
||||
|
||||
@@ -173,6 +174,11 @@ __register_host_perm_fault_handler(int (*cb)(struct user_pt_regs *regs, u64 esr,
|
||||
return mod_handler_register(HOST_FAULT_HANDLER, cb);
|
||||
}
|
||||
|
||||
static int __register_host_smc_handler(bool (*cb)(struct user_pt_regs *))
|
||||
{
|
||||
return mod_handler_register(HOST_SMC_HANDLER, cb);
|
||||
}
|
||||
|
||||
bool module_handle_host_perm_fault(struct user_pt_regs *regs, u64 esr, u64 addr)
|
||||
{
|
||||
int (*cb)(struct user_pt_regs *regs, u64 esr, u64 addr);
|
||||
@@ -186,6 +192,19 @@ bool module_handle_host_perm_fault(struct user_pt_regs *regs, u64 esr, u64 addr)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool module_handle_host_smc(struct user_pt_regs *regs)
|
||||
{
|
||||
bool (*cb)(struct user_pt_regs *regs);
|
||||
int i;
|
||||
|
||||
for_each_mod_handler(HOST_SMC_HANDLER, cb, i) {
|
||||
if (cb(regs))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const struct pkvm_module_ops module_ops = {
|
||||
.create_private_mapping = __pkvm_create_private_mapping,
|
||||
.alloc_module_va = __pkvm_alloc_module_va,
|
||||
@@ -206,7 +225,7 @@ const struct pkvm_module_ops module_ops = {
|
||||
.host_stage2_get_leaf = host_stage2_get_leaf,
|
||||
.host_stage2_enable_lazy_pte = host_stage2_enable_lazy_pte,
|
||||
.host_stage2_disable_lazy_pte = host_stage2_disable_lazy_pte,
|
||||
.register_host_smc_handler = __pkvm_register_host_smc_handler,
|
||||
.register_host_smc_handler = __register_host_smc_handler,
|
||||
.register_default_trap_handler = __pkvm_register_default_trap_handler,
|
||||
.register_illegal_abt_notifier = __pkvm_register_illegal_abt_notifier,
|
||||
.register_psci_notifier = __pkvm_register_psci_notifier,
|
||||
|
||||
Reference in New Issue
Block a user