qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH v3 26/35] arm: enable multi-arch


From: Paolo Bonzini
Subject: Re: [Qemu-devel] [PATCH v3 26/35] arm: enable multi-arch
Date: Sat, 18 Jul 2015 14:32:53 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.0.1


On 18/07/2015 11:40, Peter Crosthwaite wrote:
> Multi-arch conversion consisting of:
>  * Compiling out all target-arm private contents of cpu.h when doing
>    multi-arch build
>  * Defining the QOM cpu hooks
>  * move cp.c to hw subdir for system-level visibility
>  * Add aarch64 to multi-support list
> 
> Signed-off-by: Peter Crosthwaite <address@hidden>
> ---
> I guess I could split to multi patches but it will bloat this series!
> 
> Changed since RFC v2:
> Remove macro undefs (obsoleted)
> Remove arch prefixing redefinitions of cpu-defs symbols (obsoleted)
> Added cp.c movement.

Please add
        [core]
        renames = true

to your ~/.gitconfig or ~/.config/git/config file so that you'll get a
nicer (and easier to review) patch.

The multi-support directory is a bit weird.  Is it so ugly to do it
directly in "configure"?  Perhaps we could add CONFIG_MULTI to
default-configs/aarch64-softmmu.mak and grep in configure.  It would not
support include files, but otherwise wouldn't be a big deal, I think.

Paolo

> Remove configury changes
> Remove arch-obj changes
> ---
>  multi-support/aarch64       |   0
>  target-arm/Makefile.objs    |  25 ++--
>  target-arm/cp.c             | 328 
> --------------------------------------------
>  target-arm/cpu-qom.h        |   2 +
>  target-arm/cpu.c            |   2 +
>  target-arm/cpu.h            |  45 ++++++
>  target-arm/hw/Makefile.objs |   1 +
>  target-arm/hw/cp.c          | 328 
> ++++++++++++++++++++++++++++++++++++++++++++
>  8 files changed, 390 insertions(+), 341 deletions(-)
>  create mode 100644 multi-support/aarch64
>  delete mode 100644 target-arm/cp.c
>  create mode 100644 target-arm/hw/Makefile.objs
>  create mode 100644 target-arm/hw/cp.c
> 
> diff --git a/multi-support/aarch64 b/multi-support/aarch64
> new file mode 100644
> index 0000000..e69de29
> diff --git a/target-arm/Makefile.objs b/target-arm/Makefile.objs
> index 6d9f62e..5725c57 100644
> --- a/target-arm/Makefile.objs
> +++ b/target-arm/Makefile.objs
> @@ -1,13 +1,12 @@
> -obj-y += arm-semi.o
> -obj-$(CONFIG_SOFTMMU) += machine.o
> -obj-$(CONFIG_KVM) += kvm.o
> -obj-$(call land,$(CONFIG_KVM),$(call lnot,$(TARGET_AARCH64))) += kvm32.o
> -obj-$(call land,$(CONFIG_KVM),$(TARGET_AARCH64)) += kvm64.o
> -obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
> -obj-y += translate.o op_helper.o helper.o cpu.o
> -obj-y += cp.o
> -obj-y += neon_helper.o iwmmxt_helper.o
> -obj-y += gdbstub.o
> -obj-$(CONFIG_SOFTMMU) += psci.o
> -obj-$(TARGET_AARCH64) += cpu64.o translate-a64.o helper-a64.o gdbstub64.o
> -obj-y += crypto_helper.o
> +arch-obj-y += arm-semi.o
> +arch-obj-$(CONFIG_SOFTMMU) += machine.o
> +arch-obj-$(CONFIG_KVM) += kvm.o
> +arch-obj-$(call land,$(CONFIG_KVM),$(call lnot,$(TARGET_AARCH64))) += kvm32.o
> +arch-obj-$(call land,$(CONFIG_KVM),$(TARGET_AARCH64)) += kvm64.o
> +arch-obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
> +arch-obj-y += translate.o op_helper.o helper.o cpu.o
> +arch-obj-y += neon_helper.o iwmmxt_helper.o
> +arch-obj-y += gdbstub.o
> +arch-obj-$(CONFIG_SOFTMMU) += psci.o
> +arch-obj-$(TARGET_AARCH64) += cpu64.o translate-a64.o helper-a64.o 
> gdbstub64.o
> +arch-obj-y += crypto_helper.o
> diff --git a/target-arm/cp.c b/target-arm/cp.c
> deleted file mode 100644
> index 39a15ee..0000000
> --- a/target-arm/cp.c
> +++ /dev/null
> @@ -1,328 +0,0 @@
> -#include "qemu-common.h"
> -#include "../cpu.h"
> -
> -static bool raw_accessors_invalid(const ARMCPRegInfo *ri)
> -{
> -   /* Return true if the regdef would cause an assertion if you called
> -    * read_raw_cp_reg() or write_raw_cp_reg() on it (ie if it is a
> -    * program bug for it not to have the NO_RAW flag).
> -    * NB that returning false here doesn't necessarily mean that calling
> -    * read/write_raw_cp_reg() is safe, because we can't distinguish "has
> -    * read/write access functions which are safe for raw use" from "has
> -    * read/write access functions which have side effects but has forgotten
> -    * to provide raw access functions".
> -    * The tests here line up with the conditions in read/write_raw_cp_reg()
> -    * and assertions in raw_read()/raw_write().
> -    */
> -    if ((ri->type & ARM_CP_CONST) ||
> -        ri->fieldoffset ||
> -        ((ri->raw_writefn || ri->writefn) && (ri->raw_readfn || 
> ri->readfn))) {
> -        return false;
> -    }
> -    return true;
> -}
> -
> -static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
> -                                   void *opaque, int state, int secstate,
> -                                   int crm, int opc1, int opc2)
> -{
> -    /* Private utility function for define_one_arm_cp_reg_with_opaque():
> -     * add a single reginfo struct to the hash table.
> -     */
> -    uint32_t *key = g_new(uint32_t, 1);
> -    ARMCPRegInfo *r2 = g_memdup(r, sizeof(ARMCPRegInfo));
> -    int is64 = (r->type & ARM_CP_64BIT) ? 1 : 0;
> -    int ns = (secstate & ARM_CP_SECSTATE_NS) ? 1 : 0;
> -
> -    /* Reset the secure state to the specific incoming state.  This is
> -     * necessary as the register may have been defined with both states.
> -     */
> -    r2->secure = secstate;
> -
> -    if (r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1]) {
> -        /* Register is banked (using both entries in array).
> -         * Overwriting fieldoffset as the array is only used to define
> -         * banked registers but later only fieldoffset is used.
> -         */
> -        r2->fieldoffset = r->bank_fieldoffsets[ns];
> -    }
> -
> -    if (state == ARM_CP_STATE_AA32) {
> -        if (r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1]) {
> -            /* If the register is banked then we don't need to migrate or
> -             * reset the 32-bit instance in certain cases:
> -             *
> -             * 1) If the register has both 32-bit and 64-bit instances then 
> we
> -             *    can count on the 64-bit instance taking care of the
> -             *    non-secure bank.
> -             * 2) If ARMv8 is enabled then we can count on a 64-bit version
> -             *    taking care of the secure bank.  This requires that 
> separate
> -             *    32 and 64-bit definitions are provided.
> -             */
> -            if ((r->state == ARM_CP_STATE_BOTH && ns) ||
> -                (arm_feature(&cpu->env, ARM_FEATURE_V8) && !ns)) {
> -                r2->type |= ARM_CP_ALIAS;
> -            }
> -        } else if ((secstate != r->secure) && !ns) {
> -            /* The register is not banked so we only want to allow migration 
> of
> -             * the non-secure instance.
> -             */
> -            r2->type |= ARM_CP_ALIAS;
> -        }
> -
> -        if (r->state == ARM_CP_STATE_BOTH) {
> -            /* We assume it is a cp15 register if the .cp field is left 
> unset.
> -             */
> -            if (r2->cp == 0) {
> -                r2->cp = 15;
> -            }
> -
> -#ifdef HOST_WORDS_BIGENDIAN
> -            if (r2->fieldoffset) {
> -                r2->fieldoffset += sizeof(uint32_t);
> -            }
> -#endif
> -        }
> -    }
> -    if (state == ARM_CP_STATE_AA64) {
> -        /* To allow abbreviation of ARMCPRegInfo
> -         * definitions, we treat cp == 0 as equivalent to
> -         * the value for "standard guest-visible sysreg".
> -         * STATE_BOTH definitions are also always "standard
> -         * sysreg" in their AArch64 view (the .cp value may
> -         * be non-zero for the benefit of the AArch32 view).
> -         */
> -        if (r->cp == 0 || r->state == ARM_CP_STATE_BOTH) {
> -            r2->cp = CP_REG_ARM64_SYSREG_CP;
> -        }
> -        *key = ENCODE_AA64_CP_REG(r2->cp, r2->crn, crm,
> -                                  r2->opc0, opc1, opc2);
> -    } else {
> -        *key = ENCODE_CP_REG(r2->cp, is64, ns, r2->crn, crm, opc1, opc2);
> -    }
> -    if (opaque) {
> -        r2->opaque = opaque;
> -    }
> -    /* reginfo passed to helpers is correct for the actual access,
> -     * and is never ARM_CP_STATE_BOTH:
> -     */
> -    r2->state = state;
> -    /* Make sure reginfo passed to helpers for wildcarded regs
> -     * has the correct crm/opc1/opc2 for this reg, not CP_ANY:
> -     */
> -    r2->crm = crm;
> -    r2->opc1 = opc1;
> -    r2->opc2 = opc2;
> -    /* By convention, for wildcarded registers only the first
> -     * entry is used for migration; the others are marked as
> -     * ALIAS so we don't try to transfer the register
> -     * multiple times. Special registers (ie NOP/WFI) are
> -     * never migratable and not even raw-accessible.
> -     */
> -    if ((r->type & ARM_CP_SPECIAL)) {
> -        r2->type |= ARM_CP_NO_RAW;
> -    }
> -    if (((r->crm == CP_ANY) && crm != 0) ||
> -        ((r->opc1 == CP_ANY) && opc1 != 0) ||
> -        ((r->opc2 == CP_ANY) && opc2 != 0)) {
> -        r2->type |= ARM_CP_ALIAS;
> -    }
> -
> -    /* Check that raw accesses are either forbidden or handled. Note that
> -     * we can't assert this earlier because the setup of fieldoffset for
> -     * banked registers has to be done first.
> -     */
> -    if (!(r2->type & ARM_CP_NO_RAW)) {
> -        assert(!raw_accessors_invalid(r2));
> -    }
> -
> -    /* Overriding of an existing definition must be explicitly
> -     * requested.
> -     */
> -    if (!(r->type & ARM_CP_OVERRIDE)) {
> -        ARMCPRegInfo *oldreg;
> -        oldreg = g_hash_table_lookup(cpu->cp_regs, key);
> -        if (oldreg && !(oldreg->type & ARM_CP_OVERRIDE)) {
> -            fprintf(stderr, "Register redefined: cp=%d %d bit "
> -                    "crn=%d crm=%d opc1=%d opc2=%d, "
> -                    "was %s, now %s\n", r2->cp, 32 + 32 * is64,
> -                    r2->crn, r2->crm, r2->opc1, r2->opc2,
> -                    oldreg->name, r2->name);
> -            g_assert_not_reached();
> -        }
> -    }
> -    g_hash_table_insert(cpu->cp_regs, key, r2);
> -}
> -
> -
> -void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
> -                                       const ARMCPRegInfo *r, void *opaque)
> -{
> -    /* Define implementations of coprocessor registers.
> -     * We store these in a hashtable because typically
> -     * there are less than 150 registers in a space which
> -     * is 16*16*16*8*8 = 262144 in size.
> -     * Wildcarding is supported for the crm, opc1 and opc2 fields.
> -     * If a register is defined twice then the second definition is
> -     * used, so this can be used to define some generic registers and
> -     * then override them with implementation specific variations.
> -     * At least one of the original and the second definition should
> -     * include ARM_CP_OVERRIDE in its type bits -- this is just a guard
> -     * against accidental use.
> -     *
> -     * The state field defines whether the register is to be
> -     * visible in the AArch32 or AArch64 execution state. If the
> -     * state is set to ARM_CP_STATE_BOTH then we synthesise a
> -     * reginfo structure for the AArch32 view, which sees the lower
> -     * 32 bits of the 64 bit register.
> -     *
> -     * Only registers visible in AArch64 may set r->opc0; opc0 cannot
> -     * be wildcarded. AArch64 registers are always considered to be 64
> -     * bits; the ARM_CP_64BIT* flag applies only to the AArch32 view of
> -     * the register, if any.
> -     */
> -    int crm, opc1, opc2, state;
> -    int crmmin = (r->crm == CP_ANY) ? 0 : r->crm;
> -    int crmmax = (r->crm == CP_ANY) ? 15 : r->crm;
> -    int opc1min = (r->opc1 == CP_ANY) ? 0 : r->opc1;
> -    int opc1max = (r->opc1 == CP_ANY) ? 7 : r->opc1;
> -    int opc2min = (r->opc2 == CP_ANY) ? 0 : r->opc2;
> -    int opc2max = (r->opc2 == CP_ANY) ? 7 : r->opc2;
> -    /* 64 bit registers have only CRm and Opc1 fields */
> -    assert(!((r->type & ARM_CP_64BIT) && (r->opc2 || r->crn)));
> -    /* op0 only exists in the AArch64 encodings */
> -    assert((r->state != ARM_CP_STATE_AA32) || (r->opc0 == 0));
> -    /* AArch64 regs are all 64 bit so ARM_CP_64BIT is meaningless */
> -    assert((r->state != ARM_CP_STATE_AA64) || !(r->type & ARM_CP_64BIT));
> -    /* The AArch64 pseudocode CheckSystemAccess() specifies that op1
> -     * encodes a minimum access level for the register. We roll this
> -     * runtime check into our general permission check code, so check
> -     * here that the reginfo's specified permissions are strict enough
> -     * to encompass the generic architectural permission check.
> -     */
> -    if (r->state != ARM_CP_STATE_AA32) {
> -        int mask = 0;
> -        switch (r->opc1) {
> -        case 0: case 1: case 2:
> -            /* min_EL EL1 */
> -            mask = PL1_RW;
> -            break;
> -        case 3:
> -            /* min_EL EL0 */
> -            mask = PL0_RW;
> -            break;
> -        case 4:
> -            /* min_EL EL2 */
> -            mask = PL2_RW;
> -            break;
> -        case 5:
> -            /* unallocated encoding, so not possible */
> -            assert(false);
> -            break;
> -        case 6:
> -            /* min_EL EL3 */
> -            mask = PL3_RW;
> -            break;
> -        case 7:
> -            /* min_EL EL1, secure mode only (we don't check the latter) */
> -            mask = PL1_RW;
> -            break;
> -        default:
> -            /* broken reginfo with out-of-range opc1 */
> -            assert(false);
> -            break;
> -        }
> -        /* assert our permissions are not too lax (stricter is fine) */
> -        assert((r->access & ~mask) == 0);
> -    }
> -
> -    /* Check that the register definition has enough info to handle
> -     * reads and writes if they are permitted.
> -     */
> -    if (!(r->type & (ARM_CP_SPECIAL|ARM_CP_CONST))) {
> -        if (r->access & PL3_R) {
> -            assert((r->fieldoffset ||
> -                   (r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1])) ||
> -                   r->readfn);
> -        }
> -        if (r->access & PL3_W) {
> -            assert((r->fieldoffset ||
> -                   (r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1])) ||
> -                   r->writefn);
> -        }
> -    }
> -    /* Bad type field probably means missing sentinel at end of reg list */
> -    assert(cptype_valid(r->type));
> -    for (crm = crmmin; crm <= crmmax; crm++) {
> -        for (opc1 = opc1min; opc1 <= opc1max; opc1++) {
> -            for (opc2 = opc2min; opc2 <= opc2max; opc2++) {
> -                for (state = ARM_CP_STATE_AA32;
> -                     state <= ARM_CP_STATE_AA64; state++) {
> -                    if (r->state != state && r->state != ARM_CP_STATE_BOTH) {
> -                        continue;
> -                    }
> -                    if (state == ARM_CP_STATE_AA32) {
> -                        /* Under AArch32 CP registers can be common
> -                         * (same for secure and non-secure world) or banked.
> -                         */
> -                        switch (r->secure) {
> -                        case ARM_CP_SECSTATE_S:
> -                        case ARM_CP_SECSTATE_NS:
> -                            add_cpreg_to_hashtable(cpu, r, opaque, state,
> -                                                   r->secure, crm, opc1, 
> opc2);
> -                            break;
> -                        default:
> -                            add_cpreg_to_hashtable(cpu, r, opaque, state,
> -                                                   ARM_CP_SECSTATE_S,
> -                                                   crm, opc1, opc2);
> -                            add_cpreg_to_hashtable(cpu, r, opaque, state,
> -                                                   ARM_CP_SECSTATE_NS,
> -                                                   crm, opc1, opc2);
> -                            break;
> -                        }
> -                    } else {
> -                        /* AArch64 registers get mapped to non-secure 
> instance
> -                         * of AArch32 */
> -                        add_cpreg_to_hashtable(cpu, r, opaque, state,
> -                                               ARM_CP_SECSTATE_NS,
> -                                               crm, opc1, opc2);
> -                    }
> -                }
> -            }
> -        }
> -    }
> -}
> -
> -void define_arm_cp_regs_with_opaque(ARMCPU *cpu,
> -                                    const ARMCPRegInfo *regs, void *opaque)
> -{
> -    /* Define a whole list of registers */
> -    const ARMCPRegInfo *r;
> -    for (r = regs; r->type != ARM_CP_SENTINEL; r++) {
> -        define_one_arm_cp_reg_with_opaque(cpu, r, opaque);
> -    }
> -}
> -
> -const ARMCPRegInfo *get_arm_cp_reginfo(GHashTable *cpregs, uint32_t 
> encoded_cp)
> -{
> -    return g_hash_table_lookup(cpregs, &encoded_cp);
> -}
> -
> -void arm_cp_write_ignore(CPUARMState *env, const ARMCPRegInfo *ri,
> -                         uint64_t value)
> -{
> -    /* Helper coprocessor write function for write-ignore registers */
> -}
> -
> -uint64_t arm_cp_read_zero(CPUARMState *env, const ARMCPRegInfo *ri)
> -{
> -    /* Helper coprocessor write function for read-as-zero registers */
> -    return 0;
> -}
> -
> -void arm_cp_reset_ignore(CPUARMState *env, const ARMCPRegInfo *opaque)
> -{
> -    /* Helper coprocessor reset function for do-nothing-on-reset registers */
> -}
> -
> -
> diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
> index 3cbc4a0..77cfaf1 100644
> --- a/target-arm/cpu-qom.h
> +++ b/target-arm/cpu-qom.h
> @@ -198,9 +198,11 @@ static inline ARMCPU *arm_env_get_cpu(CPUARMState *env)
>      return container_of(env, ARMCPU, env);
>  }
>  
> +#ifndef TARGET_MULTI
>  #define ENV_GET_CPU(e) CPU(arm_env_get_cpu(e))
>  
>  #define ENV_OFFSET offsetof(ARMCPU, env)
> +#endif /* !TARGET_MULTI */
>  
>  #ifndef CONFIG_USER_ONLY
>  extern const struct VMStateDescription vmstate_arm_cpu;
> diff --git a/target-arm/cpu.c b/target-arm/cpu.c
> index 6edee95..8b5471a 100644
> --- a/target-arm/cpu.c
> +++ b/target-arm/cpu.c
> @@ -29,6 +29,7 @@
>  #include "sysemu/sysemu.h"
>  #include "sysemu/kvm.h"
>  #include "kvm_arm.h"
> +#include "tcg/tcg.h"
>  
>  static void arm_cpu_set_pc(CPUState *cs, vaddr value)
>  {
> @@ -426,6 +427,7 @@ static void arm_cpu_initfn(Object *obj)
>      static bool inited;
>      uint32_t Aff1, Aff0;
>  
> +    CPU_SET_QOM_HOOKS(cs);
>      cs->env_ptr = &cpu->env;
>      cpu_exec_init(cs, &error_abort);
>      cpu->cp_regs = g_hash_table_new_full(g_int_hash, g_int_equal,
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index 40f8551..9c53cc6 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -38,10 +38,13 @@
>  #define CPUArchState struct CPUARMState
>  
>  #include "qemu-common.h"
> +
>  #include "exec/cpu-defs.h"
>  
>  #include "fpu/softfloat.h"
>  
> +#ifndef TARGET_MULTI
> +
>  #define EXCP_UDEF            1   /* undefined instruction */
>  #define EXCP_SWI             2   /* software interrupt */
>  #define EXCP_PREFETCH_ABORT  3
> @@ -58,6 +61,10 @@
>  #define EXCP_VIRQ           14
>  #define EXCP_VFIQ           15
>  
> +#endif /* TARGET_MULTI */
> +
> +/* These defs are public as needed by ARMv7M NVIC */
> +
>  #define ARMV7M_EXCP_RESET   1
>  #define ARMV7M_EXCP_NMI     2
>  #define ARMV7M_EXCP_HARD    3
> @@ -74,6 +81,8 @@
>  #define CPU_INTERRUPT_VIRQ  CPU_INTERRUPT_TGT_EXT_2
>  #define CPU_INTERRUPT_VFIQ  CPU_INTERRUPT_TGT_EXT_3
>  
> +#ifndef TARGET_MULTI
> +
>  /* The usual mapping for an AArch64 system register to its AArch32
>   * counterpart is for the 32 bit world to have access to the lower
>   * half only (with writes leaving the upper half untouched). It's
> @@ -88,6 +97,8 @@
>  #define offsetofhigh32(S, M) (offsetof(S, M) + sizeof(uint32_t))
>  #endif
>  
> +#endif /* !TARGET_MULTI */
> +
>  /* Meanings of the ARMCPU object's four inbound GPIO lines */
>  #define ARM_CPU_IRQ 0
>  #define ARM_CPU_FIQ 1
> @@ -504,6 +515,8 @@ static inline ARMCPU *cpu_arm_init(const char *cpu_model)
>      return ARM_CPU(cpu_generic_init(TYPE_ARM_CPU, cpu_model));
>  }
>  
> +#ifndef TARGET_MULTI
> +
>  uint32_t do_arm_semihosting(CPUARMState *env);
>  void aarch64_sync_32_to_64(CPUARMState *env);
>  void aarch64_sync_64_to_32(CPUARMState *env);
> @@ -638,6 +651,12 @@ void pmccntr_sync(CPUARMState *env);
>  #define TTBCR_SH1    (1U << 28)
>  #define TTBCR_EAE    (1U << 31)
>  
> +#endif /* !TARGET_MULTI */
> +
> +/* Some bits of system level code do direct deposit to the PSTATE. Allow
> + * these symbols as global even in multi-arch.
> + */
> +
>  /* Bit definitions for ARMv8 SPSR (PSTATE) format.
>   * Only these are valid when in AArch64 mode; in
>   * AArch32 mode SPSRs are basically CPSR-format.
> @@ -667,6 +686,8 @@ void pmccntr_sync(CPUARMState *env);
>  #define PSTATE_MODE_EL1t 4
>  #define PSTATE_MODE_EL0t 0
>  
> +#ifndef TARGET_MULTI
> +
>  /* Map EL and handler into a PSTATE_MODE.  */
>  static inline unsigned int aarch64_pstate_mode(unsigned int el, bool handler)
>  {
> @@ -775,7 +796,13 @@ static inline void xpsr_write(CPUARMState *env, uint32_t 
> val, uint32_t mask)
>  #define HCR_ID        (1ULL << 33)
>  #define HCR_MASK      ((1ULL << 34) - 1)
>  
> +#endif /* !TARGET_MULTI */
> +
> +/* bootloader needs this to init security state of processor */
>  #define SCR_NS                (1U << 0)
> +
> +#ifndef TARGET_MULTI
> +
>  #define SCR_IRQ               (1U << 1)
>  #define SCR_FIQ               (1U << 2)
>  #define SCR_EA                (1U << 3)
> @@ -824,6 +851,8 @@ static inline void vfp_set_fpcr(CPUARMState *env, 
> uint32_t val)
>      vfp_set_fpscr(env, new_fpscr);
>  }
>  
> +#endif /* !TARGET_MULTI */
> +
>  enum arm_cpu_mode {
>    ARM_CPU_MODE_USR = 0x10,
>    ARM_CPU_MODE_FIQ = 0x11,
> @@ -836,6 +865,8 @@ enum arm_cpu_mode {
>    ARM_CPU_MODE_SYS = 0x1f
>  };
>  
> +#ifndef TARGET_MULTI
> +
>  /* VFP system registers.  */
>  #define ARM_VFP_FPSID   0
>  #define ARM_VFP_FPSCR   1
> @@ -856,6 +887,8 @@ enum arm_cpu_mode {
>  #define ARM_IWMMXT_wCGR2     10
>  #define ARM_IWMMXT_wCGR3     11
>  
> +#endif /* TARGET_MULTI */
> +
>  /* If adding a feature bit which corresponds to a Linux ELF
>   * HWCAP bit, remember to update the feature-bit-to-hwcap
>   * mapping in linux-user/elfload.c:get_elf_hwcap().
> @@ -912,6 +945,8 @@ static inline int arm_feature(CPUARMState *env, int 
> feature)
>      return (env->features & (1ULL << feature)) != 0;
>  }
>  
> +#ifndef TARGET_MULTI
> +
>  #if !defined(CONFIG_USER_ONLY)
>  /* Return true if exception levels below EL3 are in secure state,
>   * or would be following an exception return to that level.
> @@ -1022,6 +1057,8 @@ static inline bool access_secure_reg(CPUARMState *env)
>  uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx,
>                                   uint32_t cur_el, bool secure);
>  
> +#endif /* TARGET_MULTI */
> +
>  /* Interface between CPU and Interrupt controller.  */
>  void armv7m_nvic_set_pending(void *opaque, int irq);
>  int armv7m_nvic_acknowledge_irq(void *opaque);
> @@ -1231,6 +1268,8 @@ static inline bool cptype_valid(int cptype)
>  #define PL1_RW (PL1_R | PL1_W)
>  #define PL0_RW (PL0_R | PL0_W)
>  
> +#ifndef TARGET_MULTI
> +
>  /* Return the current Exception Level (as per ARMv8; note that this differs
>   * from the ARMv7 Privilege Level).
>   */
> @@ -1263,6 +1302,8 @@ static inline int arm_current_el(CPUARMState *env)
>      }
>  }
>  
> +#endif
> +
>  typedef struct ARMCPRegInfo ARMCPRegInfo;
>  
>  typedef enum CPAccessResult {
> @@ -1448,6 +1489,8 @@ static inline bool cp_access_ok(int current_el,
>      return (ri->access >> ((current_el * 2) + isread)) & 1;
>  }
>  
> +#ifndef TARGET_MULTI
> +
>  /**
>   * write_list_to_cpustate
>   * @cpu: ARMCPU
> @@ -1928,6 +1971,8 @@ static inline void cpu_get_tb_cpu_state(CPUARMState 
> *env, target_ulong *pc,
>  
>  #include "exec/exec-all.h"
>  
> +#endif /* !TARGET_MULTI */
> +
>  enum {
>      QEMU_PSCI_CONDUIT_DISABLED = 0,
>      QEMU_PSCI_CONDUIT_SMC = 1,
> diff --git a/target-arm/hw/Makefile.objs b/target-arm/hw/Makefile.objs
> new file mode 100644
> index 0000000..d34bbd4
> --- /dev/null
> +++ b/target-arm/hw/Makefile.objs
> @@ -0,0 +1 @@
> +obj-y += cp.o
> diff --git a/target-arm/hw/cp.c b/target-arm/hw/cp.c
> new file mode 100644
> index 0000000..39a15ee
> --- /dev/null
> +++ b/target-arm/hw/cp.c
> @@ -0,0 +1,328 @@
> +#include "qemu-common.h"
> +#include "../cpu.h"
> +
> +static bool raw_accessors_invalid(const ARMCPRegInfo *ri)
> +{
> +   /* Return true if the regdef would cause an assertion if you called
> +    * read_raw_cp_reg() or write_raw_cp_reg() on it (ie if it is a
> +    * program bug for it not to have the NO_RAW flag).
> +    * NB that returning false here doesn't necessarily mean that calling
> +    * read/write_raw_cp_reg() is safe, because we can't distinguish "has
> +    * read/write access functions which are safe for raw use" from "has
> +    * read/write access functions which have side effects but has forgotten
> +    * to provide raw access functions".
> +    * The tests here line up with the conditions in read/write_raw_cp_reg()
> +    * and assertions in raw_read()/raw_write().
> +    */
> +    if ((ri->type & ARM_CP_CONST) ||
> +        ri->fieldoffset ||
> +        ((ri->raw_writefn || ri->writefn) && (ri->raw_readfn || 
> ri->readfn))) {
> +        return false;
> +    }
> +    return true;
> +}
> +
> +static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
> +                                   void *opaque, int state, int secstate,
> +                                   int crm, int opc1, int opc2)
> +{
> +    /* Private utility function for define_one_arm_cp_reg_with_opaque():
> +     * add a single reginfo struct to the hash table.
> +     */
> +    uint32_t *key = g_new(uint32_t, 1);
> +    ARMCPRegInfo *r2 = g_memdup(r, sizeof(ARMCPRegInfo));
> +    int is64 = (r->type & ARM_CP_64BIT) ? 1 : 0;
> +    int ns = (secstate & ARM_CP_SECSTATE_NS) ? 1 : 0;
> +
> +    /* Reset the secure state to the specific incoming state.  This is
> +     * necessary as the register may have been defined with both states.
> +     */
> +    r2->secure = secstate;
> +
> +    if (r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1]) {
> +        /* Register is banked (using both entries in array).
> +         * Overwriting fieldoffset as the array is only used to define
> +         * banked registers but later only fieldoffset is used.
> +         */
> +        r2->fieldoffset = r->bank_fieldoffsets[ns];
> +    }
> +
> +    if (state == ARM_CP_STATE_AA32) {
> +        if (r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1]) {
> +            /* If the register is banked then we don't need to migrate or
> +             * reset the 32-bit instance in certain cases:
> +             *
> +             * 1) If the register has both 32-bit and 64-bit instances then 
> we
> +             *    can count on the 64-bit instance taking care of the
> +             *    non-secure bank.
> +             * 2) If ARMv8 is enabled then we can count on a 64-bit version
> +             *    taking care of the secure bank.  This requires that 
> separate
> +             *    32 and 64-bit definitions are provided.
> +             */
> +            if ((r->state == ARM_CP_STATE_BOTH && ns) ||
> +                (arm_feature(&cpu->env, ARM_FEATURE_V8) && !ns)) {
> +                r2->type |= ARM_CP_ALIAS;
> +            }
> +        } else if ((secstate != r->secure) && !ns) {
> +            /* The register is not banked so we only want to allow migration 
> of
> +             * the non-secure instance.
> +             */
> +            r2->type |= ARM_CP_ALIAS;
> +        }
> +
> +        if (r->state == ARM_CP_STATE_BOTH) {
> +            /* We assume it is a cp15 register if the .cp field is left 
> unset.
> +             */
> +            if (r2->cp == 0) {
> +                r2->cp = 15;
> +            }
> +
> +#ifdef HOST_WORDS_BIGENDIAN
> +            if (r2->fieldoffset) {
> +                r2->fieldoffset += sizeof(uint32_t);
> +            }
> +#endif
> +        }
> +    }
> +    if (state == ARM_CP_STATE_AA64) {
> +        /* To allow abbreviation of ARMCPRegInfo
> +         * definitions, we treat cp == 0 as equivalent to
> +         * the value for "standard guest-visible sysreg".
> +         * STATE_BOTH definitions are also always "standard
> +         * sysreg" in their AArch64 view (the .cp value may
> +         * be non-zero for the benefit of the AArch32 view).
> +         */
> +        if (r->cp == 0 || r->state == ARM_CP_STATE_BOTH) {
> +            r2->cp = CP_REG_ARM64_SYSREG_CP;
> +        }
> +        *key = ENCODE_AA64_CP_REG(r2->cp, r2->crn, crm,
> +                                  r2->opc0, opc1, opc2);
> +    } else {
> +        *key = ENCODE_CP_REG(r2->cp, is64, ns, r2->crn, crm, opc1, opc2);
> +    }
> +    if (opaque) {
> +        r2->opaque = opaque;
> +    }
> +    /* reginfo passed to helpers is correct for the actual access,
> +     * and is never ARM_CP_STATE_BOTH:
> +     */
> +    r2->state = state;
> +    /* Make sure reginfo passed to helpers for wildcarded regs
> +     * has the correct crm/opc1/opc2 for this reg, not CP_ANY:
> +     */
> +    r2->crm = crm;
> +    r2->opc1 = opc1;
> +    r2->opc2 = opc2;
> +    /* By convention, for wildcarded registers only the first
> +     * entry is used for migration; the others are marked as
> +     * ALIAS so we don't try to transfer the register
> +     * multiple times. Special registers (ie NOP/WFI) are
> +     * never migratable and not even raw-accessible.
> +     */
> +    if ((r->type & ARM_CP_SPECIAL)) {
> +        r2->type |= ARM_CP_NO_RAW;
> +    }
> +    if (((r->crm == CP_ANY) && crm != 0) ||
> +        ((r->opc1 == CP_ANY) && opc1 != 0) ||
> +        ((r->opc2 == CP_ANY) && opc2 != 0)) {
> +        r2->type |= ARM_CP_ALIAS;
> +    }
> +
> +    /* Check that raw accesses are either forbidden or handled. Note that
> +     * we can't assert this earlier because the setup of fieldoffset for
> +     * banked registers has to be done first.
> +     */
> +    if (!(r2->type & ARM_CP_NO_RAW)) {
> +        assert(!raw_accessors_invalid(r2));
> +    }
> +
> +    /* Overriding of an existing definition must be explicitly
> +     * requested.
> +     */
> +    if (!(r->type & ARM_CP_OVERRIDE)) {
> +        ARMCPRegInfo *oldreg;
> +        oldreg = g_hash_table_lookup(cpu->cp_regs, key);
> +        if (oldreg && !(oldreg->type & ARM_CP_OVERRIDE)) {
> +            fprintf(stderr, "Register redefined: cp=%d %d bit "
> +                    "crn=%d crm=%d opc1=%d opc2=%d, "
> +                    "was %s, now %s\n", r2->cp, 32 + 32 * is64,
> +                    r2->crn, r2->crm, r2->opc1, r2->opc2,
> +                    oldreg->name, r2->name);
> +            g_assert_not_reached();
> +        }
> +    }
> +    g_hash_table_insert(cpu->cp_regs, key, r2);
> +}
> +
> +
> +void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
> +                                       const ARMCPRegInfo *r, void *opaque)
> +{
> +    /* Define implementations of coprocessor registers.
> +     * We store these in a hashtable because typically
> +     * there are less than 150 registers in a space which
> +     * is 16*16*16*8*8 = 262144 in size.
> +     * Wildcarding is supported for the crm, opc1 and opc2 fields.
> +     * If a register is defined twice then the second definition is
> +     * used, so this can be used to define some generic registers and
> +     * then override them with implementation specific variations.
> +     * At least one of the original and the second definition should
> +     * include ARM_CP_OVERRIDE in its type bits -- this is just a guard
> +     * against accidental use.
> +     *
> +     * The state field defines whether the register is to be
> +     * visible in the AArch32 or AArch64 execution state. If the
> +     * state is set to ARM_CP_STATE_BOTH then we synthesise a
> +     * reginfo structure for the AArch32 view, which sees the lower
> +     * 32 bits of the 64 bit register.
> +     *
> +     * Only registers visible in AArch64 may set r->opc0; opc0 cannot
> +     * be wildcarded. AArch64 registers are always considered to be 64
> +     * bits; the ARM_CP_64BIT* flag applies only to the AArch32 view of
> +     * the register, if any.
> +     */
> +    int crm, opc1, opc2, state;
> +    int crmmin = (r->crm == CP_ANY) ? 0 : r->crm;
> +    int crmmax = (r->crm == CP_ANY) ? 15 : r->crm;
> +    int opc1min = (r->opc1 == CP_ANY) ? 0 : r->opc1;
> +    int opc1max = (r->opc1 == CP_ANY) ? 7 : r->opc1;
> +    int opc2min = (r->opc2 == CP_ANY) ? 0 : r->opc2;
> +    int opc2max = (r->opc2 == CP_ANY) ? 7 : r->opc2;
> +    /* 64 bit registers have only CRm and Opc1 fields */
> +    assert(!((r->type & ARM_CP_64BIT) && (r->opc2 || r->crn)));
> +    /* op0 only exists in the AArch64 encodings */
> +    assert((r->state != ARM_CP_STATE_AA32) || (r->opc0 == 0));
> +    /* AArch64 regs are all 64 bit so ARM_CP_64BIT is meaningless */
> +    assert((r->state != ARM_CP_STATE_AA64) || !(r->type & ARM_CP_64BIT));
> +    /* The AArch64 pseudocode CheckSystemAccess() specifies that op1
> +     * encodes a minimum access level for the register. We roll this
> +     * runtime check into our general permission check code, so check
> +     * here that the reginfo's specified permissions are strict enough
> +     * to encompass the generic architectural permission check.
> +     */
> +    if (r->state != ARM_CP_STATE_AA32) {
> +        int mask = 0;
> +        switch (r->opc1) {
> +        case 0: case 1: case 2:
> +            /* min_EL EL1 */
> +            mask = PL1_RW;
> +            break;
> +        case 3:
> +            /* min_EL EL0 */
> +            mask = PL0_RW;
> +            break;
> +        case 4:
> +            /* min_EL EL2 */
> +            mask = PL2_RW;
> +            break;
> +        case 5:
> +            /* unallocated encoding, so not possible */
> +            assert(false);
> +            break;
> +        case 6:
> +            /* min_EL EL3 */
> +            mask = PL3_RW;
> +            break;
> +        case 7:
> +            /* min_EL EL1, secure mode only (we don't check the latter) */
> +            mask = PL1_RW;
> +            break;
> +        default:
> +            /* broken reginfo with out-of-range opc1 */
> +            assert(false);
> +            break;
> +        }
> +        /* assert our permissions are not too lax (stricter is fine) */
> +        assert((r->access & ~mask) == 0);
> +    }
> +
> +    /* Check that the register definition has enough info to handle
> +     * reads and writes if they are permitted.
> +     */
> +    if (!(r->type & (ARM_CP_SPECIAL|ARM_CP_CONST))) {
> +        if (r->access & PL3_R) {
> +            assert((r->fieldoffset ||
> +                   (r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1])) ||
> +                   r->readfn);
> +        }
> +        if (r->access & PL3_W) {
> +            assert((r->fieldoffset ||
> +                   (r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1])) ||
> +                   r->writefn);
> +        }
> +    }
> +    /* Bad type field probably means missing sentinel at end of reg list */
> +    assert(cptype_valid(r->type));
> +    for (crm = crmmin; crm <= crmmax; crm++) {
> +        for (opc1 = opc1min; opc1 <= opc1max; opc1++) {
> +            for (opc2 = opc2min; opc2 <= opc2max; opc2++) {
> +                for (state = ARM_CP_STATE_AA32;
> +                     state <= ARM_CP_STATE_AA64; state++) {
> +                    if (r->state != state && r->state != ARM_CP_STATE_BOTH) {
> +                        continue;
> +                    }
> +                    if (state == ARM_CP_STATE_AA32) {
> +                        /* Under AArch32 CP registers can be common
> +                         * (same for secure and non-secure world) or banked.
> +                         */
> +                        switch (r->secure) {
> +                        case ARM_CP_SECSTATE_S:
> +                        case ARM_CP_SECSTATE_NS:
> +                            add_cpreg_to_hashtable(cpu, r, opaque, state,
> +                                                   r->secure, crm, opc1, 
> opc2);
> +                            break;
> +                        default:
> +                            add_cpreg_to_hashtable(cpu, r, opaque, state,
> +                                                   ARM_CP_SECSTATE_S,
> +                                                   crm, opc1, opc2);
> +                            add_cpreg_to_hashtable(cpu, r, opaque, state,
> +                                                   ARM_CP_SECSTATE_NS,
> +                                                   crm, opc1, opc2);
> +                            break;
> +                        }
> +                    } else {
> +                        /* AArch64 registers get mapped to non-secure 
> instance
> +                         * of AArch32 */
> +                        add_cpreg_to_hashtable(cpu, r, opaque, state,
> +                                               ARM_CP_SECSTATE_NS,
> +                                               crm, opc1, opc2);
> +                    }
> +                }
> +            }
> +        }
> +    }
> +}
> +
> +void define_arm_cp_regs_with_opaque(ARMCPU *cpu,
> +                                    const ARMCPRegInfo *regs, void *opaque)
> +{
> +    /* Define a whole list of registers */
> +    const ARMCPRegInfo *r;
> +    for (r = regs; r->type != ARM_CP_SENTINEL; r++) {
> +        define_one_arm_cp_reg_with_opaque(cpu, r, opaque);
> +    }
> +}
> +
> +const ARMCPRegInfo *get_arm_cp_reginfo(GHashTable *cpregs, uint32_t 
> encoded_cp)
> +{
> +    return g_hash_table_lookup(cpregs, &encoded_cp);
> +}
> +
> +void arm_cp_write_ignore(CPUARMState *env, const ARMCPRegInfo *ri,
> +                         uint64_t value)
> +{
> +    /* Helper coprocessor write function for write-ignore registers */
> +}
> +
> +uint64_t arm_cp_read_zero(CPUARMState *env, const ARMCPRegInfo *ri)
> +{
> +    /* Helper coprocessor write function for read-as-zero registers */
> +    return 0;
> +}
> +
> +void arm_cp_reset_ignore(CPUARMState *env, const ARMCPRegInfo *opaque)
> +{
> +    /* Helper coprocessor reset function for do-nothing-on-reset registers */
> +}
> +
> +
> 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]