Commit b5c53d1b authored by Aaron Lindsay's avatar Aaron Lindsay Committed by Peter Maydell
Browse files

target/arm: Add pre-EL change hooks



Because the design of the PMU requires that the counter values be
converted between their delta and guest-visible forms for mode
filtering, an additional hook which occurs before the EL is changed is
necessary.

Signed-off-by: default avatarAaron Lindsay <alindsay@codeaurora.org>
Message-id: 1523997485-1905-8-git-send-email-alindsay@codeaurora.org
Reviewed-by: default avatarPeter Maydell <peter.maydell@linaro.org>
Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parent 08267487
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -55,6 +55,17 @@ static bool arm_cpu_has_work(CPUState *cs)
         | CPU_INTERRUPT_EXITTB);
}

void arm_register_pre_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook,
                                 void *opaque)
{
    ARMELChangeHook *entry = g_new0(ARMELChangeHook, 1);

    entry->hook = hook;
    entry->opaque = opaque;

    QLIST_INSERT_HEAD(&cpu->pre_el_change_hooks, entry, node);
}

void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook,
                                 void *opaque)
{
@@ -554,6 +565,7 @@ static void arm_cpu_initfn(Object *obj)
    cpu->cp_regs = g_hash_table_new_full(g_int_hash, g_int_equal,
                                         g_free, g_free);

    QLIST_INIT(&cpu->pre_el_change_hooks);
    QLIST_INIT(&cpu->el_change_hooks);

#ifndef CONFIG_USER_ONLY
@@ -721,6 +733,10 @@ static void arm_cpu_finalizefn(Object *obj)

    g_hash_table_destroy(cpu->cp_regs);

    QLIST_FOREACH_SAFE(hook, &cpu->pre_el_change_hooks, node, next) {
        QLIST_REMOVE(hook, node);
        g_free(hook);
    }
    QLIST_FOREACH_SAFE(hook, &cpu->el_change_hooks, node, next) {
        QLIST_REMOVE(hook, node);
        g_free(hook);
+19 −3
Original line number Diff line number Diff line
@@ -831,6 +831,7 @@ struct ARMCPU {
     */
    bool cfgend;

    QLIST_HEAD(, ARMELChangeHook) pre_el_change_hooks;
    QLIST_HEAD(, ARMELChangeHook) el_change_hooks;

    int32_t node_id; /* NUMA node this CPU belongs to */
@@ -2893,14 +2894,29 @@ static inline AddressSpace *arm_addressspace(CPUState *cs, MemTxAttrs attrs)
#endif

/**
 * arm_register_el_change_hook:
 * Register a hook function which will be called back whenever this
 * arm_register_pre_el_change_hook:
 * Register a hook function which will be called immediately before this
 * 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 if a pre-change hook is called, any registered post-change hooks
 * are guaranteed to subsequently be called.
 */
void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook,
void arm_register_pre_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook,
                                 void *opaque);
/**
 * arm_register_el_change_hook:
 * Register a hook function which will be called immediately after this
 * 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 any registered hooks registered here are guaranteed to be called
 * if pre-change hooks have been.
 */
void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook, void
        *opaque);

/**
 * aa32_vfp_dreg:
+8 −6
Original line number Diff line number Diff line
@@ -8249,6 +8249,14 @@ void arm_cpu_do_interrupt(CPUState *cs)
        return;
    }

    /* Hooks may change global state so BQL should be held, also the
     * BQL needs to be held for any modification of
     * cs->interrupt_request.
     */
    g_assert(qemu_mutex_iothread_locked());

    arm_call_pre_el_change_hook(cpu);

    assert(!excp_is_internal(cs->exception_index));
    if (arm_el_is_aa64(env, new_el)) {
        arm_cpu_do_interrupt_aarch64(cs);
@@ -8256,12 +8264,6 @@ void arm_cpu_do_interrupt(CPUState *cs)
        arm_cpu_do_interrupt_aarch32(cs);
    }

    /* Hooks may change global state so BQL should be held, also the
     * BQL needs to be held for any modification of
     * cs->interrupt_request.
     */
    g_assert(qemu_mutex_iothread_locked());

    arm_call_el_change_hook(cpu);

    if (!kvm_enabled()) {
+7 −0
Original line number Diff line number Diff line
@@ -728,6 +728,13 @@ void arm_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
                                   MemTxResult response, uintptr_t retaddr);

/* Call any registered EL change hooks */
static inline void arm_call_pre_el_change_hook(ARMCPU *cpu)
{
    ARMELChangeHook *hook, *next;
    QLIST_FOREACH_SAFE(hook, &cpu->pre_el_change_hooks, node, next) {
        hook->hook(cpu, hook->opaque);
    }
}
static inline void arm_call_el_change_hook(ARMCPU *cpu)
{
    ARMELChangeHook *hook, *next;
+8 −0
Original line number Diff line number Diff line
@@ -511,6 +511,10 @@ void HELPER(cpsr_write)(CPUARMState *env, uint32_t val, uint32_t mask)
/* Write the CPSR for a 32-bit exception return */
void HELPER(cpsr_write_eret)(CPUARMState *env, uint32_t val)
{
    qemu_mutex_lock_iothread();
    arm_call_pre_el_change_hook(arm_env_get_cpu(env));
    qemu_mutex_unlock_iothread();

    cpsr_write(env, val, CPSR_ERET_MASK, CPSRWriteExceptionReturn);

    /* Generated code has already stored the new PC value, but
@@ -1028,6 +1032,10 @@ void HELPER(exception_return)(CPUARMState *env)
        goto illegal_return;
    }

    qemu_mutex_lock_iothread();
    arm_call_pre_el_change_hook(arm_env_get_cpu(env));
    qemu_mutex_unlock_iothread();

    if (!return_to_aa64) {
        env->aarch64 = 0;
        /* We do a raw CPSR write because aarch64_sync_64_to_32()