Signed-off-by: Aaron Lindsay <alind...@codeaurora.org> --- target/arm/cpu.c | 15 ++++++++++----- target/arm/cpu.h | 23 ++++++++++++----------- target/arm/internals.h | 7 ++++--- 3 files changed, 26 insertions(+), 19 deletions(-)
diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 072cbbf..5f782bf 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -55,13 +55,16 @@ static bool arm_cpu_has_work(CPUState *cs) | CPU_INTERRUPT_EXITTB); } -void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHook *hook, +void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook, void *opaque) { - /* We currently only support registering a single hook function */ - assert(!cpu->el_change_hook); - cpu->el_change_hook = hook; - cpu->el_change_hook_opaque = opaque; + ARMELChangeHook *entry; + entry = g_malloc0(sizeof (*entry)); + + entry->hook = hook; + entry->opaque = opaque; + + QLIST_INSERT_HEAD(&cpu->el_change_hooks, entry, node); } static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque) @@ -744,6 +747,8 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) return; } + QLIST_INIT(&cpu->el_change_hooks); + /* Some features automatically imply others: */ if (arm_feature(env, ARM_FEATURE_V8)) { set_feature(env, ARM_FEATURE_V7); diff --git a/target/arm/cpu.h b/target/arm/cpu.h index f17592b..3b45d3d 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -633,11 +633,17 @@ typedef struct CPUARMState { /** * ARMELChangeHook: - * type of a function which can be registered via arm_register_el_change_hook() - * to get callbacks when the CPU changes its exception level or mode. + * Support registering functions with ARMELChangeHookFn's signature via + * arm_register_el_change_hook() to get callbacks when the CPU changes its + * exception level or mode. */ -typedef void ARMELChangeHook(ARMCPU *cpu, void *opaque); - +typedef void ARMELChangeHookFn(ARMCPU *cpu, void *opaque); +typedef struct ARMELChangeHook ARMELChangeHook; +struct ARMELChangeHook { + ARMELChangeHookFn *hook; + void *opaque; + QLIST_ENTRY(ARMELChangeHook) node; +}; /* These values map onto the return values for * QEMU_PSCI_0_2_FN_AFFINITY_INFO */ @@ -826,8 +832,7 @@ struct ARMCPU { */ bool cfgend; - ARMELChangeHook *el_change_hook; - void *el_change_hook_opaque; + QLIST_HEAD(, ARMELChangeHook) el_change_hooks; int32_t node_id; /* NUMA node this CPU belongs to */ @@ -2895,12 +2900,8 @@ static inline AddressSpace *arm_addressspace(CPUState *cs, MemTxAttrs attrs) * CPU changes exception level or mode. The hook function will be * passed a pointer to the ARMCPU and the opaque data pointer passed * to this function when the hook was registered. - * - * Note that we currently only support registering a single hook function, - * and will assert if this function is called twice. - * This facility is intended for the use of the GICv3 emulation. */ -void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHook *hook, +void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook, void *opaque); /** diff --git a/target/arm/internals.h b/target/arm/internals.h index 47cc224..7df3eda 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -727,11 +727,12 @@ void arm_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, int mmu_idx, MemTxAttrs attrs, MemTxResult response, uintptr_t retaddr); -/* Call the EL change hook if one has been registered */ +/* Call any registered EL change hooks */ static inline void arm_call_el_change_hook(ARMCPU *cpu) { - if (cpu->el_change_hook) { - cpu->el_change_hook(cpu, cpu->el_change_hook_opaque); + ARMELChangeHook *hook, *next; + QLIST_FOREACH_SAFE(hook, &cpu->el_change_hooks, node, next) { + hook->hook(cpu, hook->opaque); } } -- Qualcomm Datacenter Technologies as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.