From 200bf596b96820186883953de9bda26cac8e6bd7 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jun 2012 11:57:06 +0000 Subject: target-arm: Fix 11MPCore cache type register value Make the 11MPCore report a valid value in its cache type register (the previous value appears to have been incorrectly copied from the 1136/1176). In particular, do not report that we have an aliasing VIPT cache, because this causes Linux to attempt to use the v6 block cache ops which the 11MPCore doesn't actually have. (This causes no problems currently because we over-broadly provide those ops on all cores, but prevents us correctly narrowing the block ops down to those cores which actually implement them.) Signed-off-by: Peter Maydell --- target-arm/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-arm/cpu.c b/target-arm/cpu.c index 7eb323ae4d..934894bf93 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -307,7 +307,7 @@ static void arm11mpcore_initfn(Object *obj) cpu->reset_fpsid = 0x410120b4; cpu->mvfr0 = 0x11111111; cpu->mvfr1 = 0x00000000; - cpu->ctr = 0x1dd20d2; + cpu->ctr = 0x1d192992; /* 32K icache 32K dcache */ cpu->id_pfr0 = 0x111; cpu->id_pfr1 = 0x1; cpu->id_dfr0 = 0; -- cgit v1.2.3 From 4b6a83fb0c34a6fcc7bb1058284e3c3674e54421 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jun 2012 11:57:06 +0000 Subject: target-arm: initial coprocessor register framework Initial infrastructure for data-driven registration of coprocessor register implementations. We still fall back to the old-style switch statements pending complete conversion of all existing registers. Signed-off-by: Peter Maydell --- target-arm/cpu-qom.h | 3 + target-arm/cpu.c | 41 ++++++++++ target-arm/cpu.h | 201 +++++++++++++++++++++++++++++++++++++++++++++++++ target-arm/helper.c | 101 +++++++++++++++++++++++++ target-arm/helper.h | 5 ++ target-arm/op_helper.c | 42 ++++++++++- target-arm/translate.c | 156 +++++++++++++++++++++++++++++++++++++- 7 files changed, 546 insertions(+), 3 deletions(-) diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h index a61c68d21b..848ac2ffdf 100644 --- a/target-arm/cpu-qom.h +++ b/target-arm/cpu-qom.h @@ -58,6 +58,9 @@ typedef struct ARMCPU { CPUARMState env; + /* Coprocessor information */ + GHashTable *cp_regs; + /* The instance init functions for implementation-specific subclasses * set these fields to specify the implementation-dependent values of * various constant registers and reset values of non-constant diff --git a/target-arm/cpu.c b/target-arm/cpu.c index 934894bf93..6456a3dfa8 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -24,6 +24,37 @@ #include "hw/loader.h" #endif +static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque) +{ + /* Reset a single ARMCPRegInfo register */ + ARMCPRegInfo *ri = value; + ARMCPU *cpu = opaque; + + if (ri->type & ARM_CP_SPECIAL) { + return; + } + + if (ri->resetfn) { + ri->resetfn(&cpu->env, ri); + return; + } + + /* A zero offset is never possible as it would be regs[0] + * so we use it to indicate that reset is being handled elsewhere. + * This is basically only used for fields in non-core coprocessors + * (like the pxa2xx ones). + */ + if (!ri->fieldoffset) { + return; + } + + if (ri->type & ARM_CP_64BIT) { + CPREG_FIELD64(&cpu->env, ri) = ri->resetvalue; + } else { + CPREG_FIELD32(&cpu->env, ri) = ri->resetvalue; + } +} + /* CPUClass::reset() */ static void arm_cpu_reset(CPUState *s) { @@ -39,6 +70,7 @@ static void arm_cpu_reset(CPUState *s) acc->parent_reset(s); memset(env, 0, offsetof(CPUARMState, breakpoints)); + g_hash_table_foreach(cpu->cp_regs, cp_reg_reset, cpu); env->cp15.c15_config_base_address = cpu->reset_cbar; env->cp15.c0_cpuid = cpu->midr; env->vfp.xregs[ARM_VFP_FPSID] = cpu->reset_fpsid; @@ -130,6 +162,14 @@ static void arm_cpu_initfn(Object *obj) ARMCPU *cpu = ARM_CPU(obj); cpu_exec_init(&cpu->env); + cpu->cp_regs = g_hash_table_new_full(g_int_hash, g_int_equal, + g_free, g_free); +} + +static void arm_cpu_finalizefn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + g_hash_table_destroy(cpu->cp_regs); } void arm_cpu_realize(ARMCPU *cpu) @@ -657,6 +697,7 @@ static const TypeInfo arm_cpu_type_info = { .parent = TYPE_CPU, .instance_size = sizeof(ARMCPU), .instance_init = arm_cpu_initfn, + .instance_finalize = arm_cpu_finalizefn, .abstract = true, .class_size = sizeof(ARMCPUClass), .class_init = arm_cpu_class_init, diff --git a/target-arm/cpu.h b/target-arm/cpu.h index d01285fd57..6c7d3e72e0 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -410,6 +410,207 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum, ARMReadCPFunc *cp_read, ARMWriteCPFunc *cp_write, void *opaque); +/* Interface for defining coprocessor registers. + * Registers are defined in tables of arm_cp_reginfo structs + * which are passed to define_arm_cp_regs(). + */ + +/* When looking up a coprocessor register we look for it + * via an integer which encodes all of: + * coprocessor number + * Crn, Crm, opc1, opc2 fields + * 32 or 64 bit register (ie is it accessed via MRC/MCR + * or via MRRC/MCRR?) + * We allow 4 bits for opc1 because MRRC/MCRR have a 4 bit field. + * (In this case crn and opc2 should be zero.) + */ +#define ENCODE_CP_REG(cp, is64, crn, crm, opc1, opc2) \ + (((cp) << 16) | ((is64) << 15) | ((crn) << 11) | \ + ((crm) << 7) | ((opc1) << 3) | (opc2)) + +#define DECODE_CPREG_CRN(enc) (((enc) >> 7) & 0xf) + +/* ARMCPRegInfo type field bits. If the SPECIAL bit is set this is a + * special-behaviour cp reg and bits [15..8] indicate what behaviour + * it has. Otherwise it is a simple cp reg, where CONST indicates that + * TCG can assume the value to be constant (ie load at translate time) + * and 64BIT indicates a 64 bit wide coprocessor register. SUPPRESS_TB_END + * indicates that the TB should not be ended after a write to this register + * (the default is that the TB ends after cp writes). OVERRIDE permits + * a register definition to override a previous definition for the + * same (cp, is64, crn, crm, opc1, opc2) tuple: either the new or the + * old must have the OVERRIDE bit set. + */ +#define ARM_CP_SPECIAL 1 +#define ARM_CP_CONST 2 +#define ARM_CP_64BIT 4 +#define ARM_CP_SUPPRESS_TB_END 8 +#define ARM_CP_OVERRIDE 16 +#define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 8)) +#define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 8)) +#define ARM_LAST_SPECIAL ARM_CP_WFI +/* Used only as a terminator for ARMCPRegInfo lists */ +#define ARM_CP_SENTINEL 0xffff +/* Mask of only the flag bits in a type field */ +#define ARM_CP_FLAG_MASK 0x1f + +/* Return true if cptype is a valid type field. This is used to try to + * catch errors where the sentinel has been accidentally left off the end + * of a list of registers. + */ +static inline bool cptype_valid(int cptype) +{ + return ((cptype & ~ARM_CP_FLAG_MASK) == 0) + || ((cptype & ARM_CP_SPECIAL) && + (cptype <= ARM_LAST_SPECIAL)); +} + +/* Access rights: + * We define bits for Read and Write access for what rev C of the v7-AR ARM ARM + * defines as PL0 (user), PL1 (fiq/irq/svc/abt/und/sys, ie privileged), and + * PL2 (hyp). The other level which has Read and Write bits is Secure PL1 + * (ie any of the privileged modes in Secure state, or Monitor mode). + * If a register is accessible in one privilege level it's always accessible + * in higher privilege levels too. Since "Secure PL1" also follows this rule + * (ie anything visible in PL2 is visible in S-PL1, some things are only + * visible in S-PL1) but "Secure PL1" is a bit of a mouthful, we bend the + * terminology a little and call this PL3. + * + * If access permissions for a register are more complex than can be + * described with these bits, then use a laxer set of restrictions, and + * do the more restrictive/complex check inside a helper function. + */ +#define PL3_R 0x80 +#define PL3_W 0x40 +#define PL2_R (0x20 | PL3_R) +#define PL2_W (0x10 | PL3_W) +#define PL1_R (0x08 | PL2_R) +#define PL1_W (0x04 | PL2_W) +#define PL0_R (0x02 | PL1_R) +#define PL0_W (0x01 | PL1_W) + +#define PL3_RW (PL3_R | PL3_W) +#define PL2_RW (PL2_R | PL2_W) +#define PL1_RW (PL1_R | PL1_W) +#define PL0_RW (PL0_R | PL0_W) + +static inline int arm_current_pl(CPUARMState *env) +{ + if ((env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_USR) { + return 0; + } + /* We don't currently implement the Virtualization or TrustZone + * extensions, so PL2 and PL3 don't exist for us. + */ + return 1; +} + +typedef struct ARMCPRegInfo ARMCPRegInfo; + +/* Access functions for coprocessor registers. These should return + * 0 on success, or one of the EXCP_* constants if access should cause + * an exception (in which case *value is not written). + */ +typedef int CPReadFn(CPUARMState *env, const ARMCPRegInfo *opaque, + uint64_t *value); +typedef int CPWriteFn(CPUARMState *env, const ARMCPRegInfo *opaque, + uint64_t value); +/* Hook function for register reset */ +typedef void CPResetFn(CPUARMState *env, const ARMCPRegInfo *opaque); + +#define CP_ANY 0xff + +/* Definition of an ARM coprocessor register */ +struct ARMCPRegInfo { + /* Name of register (useful mainly for debugging, need not be unique) */ + const char *name; + /* Location of register: coprocessor number and (crn,crm,opc1,opc2) + * tuple. Any of crm, opc1 and opc2 may be CP_ANY to indicate a + * 'wildcard' field -- any value of that field in the MRC/MCR insn + * will be decoded to this register. The register read and write + * callbacks will be passed an ARMCPRegInfo with the crn/crm/opc1/opc2 + * used by the program, so it is possible to register a wildcard and + * then behave differently on read/write if necessary. + * For 64 bit registers, only crm and opc1 are relevant; crn and opc2 + * must both be zero. + */ + uint8_t cp; + uint8_t crn; + uint8_t crm; + uint8_t opc1; + uint8_t opc2; + /* Register type: ARM_CP_* bits/values */ + int type; + /* Access rights: PL*_[RW] */ + int access; + /* The opaque pointer passed to define_arm_cp_regs_with_opaque() when + * this register was defined: can be used to hand data through to the + * register read/write functions, since they are passed the ARMCPRegInfo*. + */ + void *opaque; + /* Value of this register, if it is ARM_CP_CONST. Otherwise, if + * fieldoffset is non-zero, the reset value of the register. + */ + uint64_t resetvalue; + /* Offset of the field in CPUARMState for this register. This is not + * needed if either: + * 1. type is ARM_CP_CONST or one of the ARM_CP_SPECIALs + * 2. both readfn and writefn are specified + */ + ptrdiff_t fieldoffset; /* offsetof(CPUARMState, field) */ + /* Function for handling reads of this register. If NULL, then reads + * will be done by loading from the offset into CPUARMState specified + * by fieldoffset. + */ + CPReadFn *readfn; + /* Function for handling writes of this register. If NULL, then writes + * will be done by writing to the offset into CPUARMState specified + * by fieldoffset. + */ + CPWriteFn *writefn; + /* Function for resetting the register. If NULL, then reset will be done + * by writing resetvalue to the field specified in fieldoffset. If + * fieldoffset is 0 then no reset will be done. + */ + CPResetFn *resetfn; +}; + +/* Macros which are lvalues for the field in CPUARMState for the + * ARMCPRegInfo *ri. + */ +#define CPREG_FIELD32(env, ri) \ + (*(uint32_t *)((char *)(env) + (ri)->fieldoffset)) +#define CPREG_FIELD64(env, ri) \ + (*(uint64_t *)((char *)(env) + (ri)->fieldoffset)) + +#define REGINFO_SENTINEL { .type = ARM_CP_SENTINEL } + +void define_arm_cp_regs_with_opaque(ARMCPU *cpu, + const ARMCPRegInfo *regs, void *opaque); +void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, + const ARMCPRegInfo *regs, void *opaque); +static inline void define_arm_cp_regs(ARMCPU *cpu, const ARMCPRegInfo *regs) +{ + define_arm_cp_regs_with_opaque(cpu, regs, 0); +} +static inline void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *regs) +{ + define_one_arm_cp_reg_with_opaque(cpu, regs, 0); +} +const ARMCPRegInfo *get_arm_cp_reginfo(ARMCPU *cpu, uint32_t encoded_cp); + +/* CPWriteFn that can be used to implement writes-ignored behaviour */ +int arm_cp_write_ignore(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value); +/* CPReadFn that can be used for read-as-zero behaviour */ +int arm_cp_read_zero(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t *value); + +static inline bool cp_access_ok(CPUARMState *env, + const ARMCPRegInfo *ri, int isread) +{ + return (ri->access >> ((arm_current_pl(env) * 2) + isread)) & 1; +} + /* Does the core conform to the the "MicroController" profile. e.g. Cortex-M3. Note the M in older cores (eg. ARM7TDMI) stands for Multiply. These are conventional cores (ie. Application or Realtime profile). */ diff --git a/target-arm/helper.c b/target-arm/helper.c index bbb1d05d10..70324234ec 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -137,6 +137,107 @@ void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf) g_slist_free(list); } +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. + */ + int crm, opc1, opc2; + 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))); + /* 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->readfn); + } + if (r->access & PL3_W) { + assert(r->fieldoffset || 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++) { + uint32_t *key = g_new(uint32_t, 1); + ARMCPRegInfo *r2 = g_memdup(r, sizeof(ARMCPRegInfo)); + int is64 = (r->type & ARM_CP_64BIT) ? 1 : 0; + *key = ENCODE_CP_REG(r->cp, is64, r->crn, crm, opc1, opc2); + r2->opaque = opaque; + /* 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; + /* 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); + assert(0); + } + } + g_hash_table_insert(cpu->cp_regs, key, r2); + } + } + } +} + +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(ARMCPU *cpu, uint32_t encoded_cp) +{ + return g_hash_table_lookup(cpu->cp_regs, &encoded_cp); +} + +int arm_cp_write_ignore(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + /* Helper coprocessor write function for write-ignore registers */ + return 0; +} + +int arm_cp_read_zero(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t *value) +{ + /* Helper coprocessor write function for read-as-zero registers */ + *value = 0; + return 0; +} + static int bad_mode_switch(CPUARMState *env, int mode) { /* Return true if it is not valid for us to switch to diff --git a/target-arm/helper.h b/target-arm/helper.h index 16dd5fcc89..b6cefed206 100644 --- a/target-arm/helper.h +++ b/target-arm/helper.h @@ -65,6 +65,11 @@ DEF_HELPER_2(get_cp15, i32, env, i32) DEF_HELPER_3(set_cp, void, env, i32, i32) DEF_HELPER_2(get_cp, i32, env, i32) +DEF_HELPER_3(set_cp_reg, void, env, ptr, i32) +DEF_HELPER_2(get_cp_reg, i32, env, ptr) +DEF_HELPER_3(set_cp_reg64, void, env, ptr, i64) +DEF_HELPER_2(get_cp_reg64, i64, env, ptr) + DEF_HELPER_2(get_r13_banked, i32, env, i32) DEF_HELPER_3(set_r13_banked, void, env, i32, i32) diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index b53369d7cb..490111c22f 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -23,13 +23,11 @@ #define SIGNBIT (uint32_t)0x80000000 #define SIGNBIT64 ((uint64_t)1 << 63) -#if !defined(CONFIG_USER_ONLY) static void raise_exception(int tt) { env->exception_index = tt; cpu_loop_exit(env); } -#endif uint32_t HELPER(neon_tbl)(uint32_t ireg, uint32_t def, uint32_t rn, uint32_t maxindex) @@ -287,6 +285,46 @@ void HELPER(set_user_reg)(uint32_t regno, uint32_t val) } } +void HELPER(set_cp_reg)(CPUARMState *env, void *rip, uint32_t value) +{ + const ARMCPRegInfo *ri = rip; + int excp = ri->writefn(env, ri, value); + if (excp) { + raise_exception(excp); + } +} + +uint32_t HELPER(get_cp_reg)(CPUARMState *env, void *rip) +{ + const ARMCPRegInfo *ri = rip; + uint64_t value; + int excp = ri->readfn(env, ri, &value); + if (excp) { + raise_exception(excp); + } + return value; +} + +void HELPER(set_cp_reg64)(CPUARMState *env, void *rip, uint64_t value) +{ + const ARMCPRegInfo *ri = rip; + int excp = ri->writefn(env, ri, value); + if (excp) { + raise_exception(excp); + } +} + +uint64_t HELPER(get_cp_reg64)(CPUARMState *env, void *rip) +{ + const ARMCPRegInfo *ri = rip; + uint64_t value; + int excp = ri->readfn(env, ri, &value); + if (excp) { + raise_exception(excp); + } + return value; +} + /* ??? Flag setting arithmetic is awkward because we need to do comparisons. The only way to do that in TCG is a conditional branch, which clobbers all our temporaries. For now implement these as helper functions. */ diff --git a/target-arm/translate.c b/target-arm/translate.c index 437d9dbf0e..d7edda758e 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -6479,13 +6479,16 @@ static int disas_cp14_write(CPUARMState * env, DisasContext *s, uint32_t insn) static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn) { - int cpnum; + int cpnum, is64, crn, crm, opc1, opc2, isread, rt, rt2; + const ARMCPRegInfo *ri; + ARMCPU *cpu = arm_env_get_cpu(env); cpnum = (insn >> 8) & 0xf; if (arm_feature(env, ARM_FEATURE_XSCALE) && ((env->cp15.c15_cpar ^ 0x3fff) & (1 << cpnum))) return 1; + /* First check for coprocessor space used for actual instructions */ switch (cpnum) { case 0: case 1: @@ -6498,6 +6501,157 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn) case 10: case 11: return disas_vfp_insn (env, s, insn); + default: + break; + } + + /* Otherwise treat as a generic register access */ + is64 = (insn & (1 << 25)) == 0; + if (!is64 && ((insn & (1 << 4)) == 0)) { + /* cdp */ + return 1; + } + + crm = insn & 0xf; + if (is64) { + crn = 0; + opc1 = (insn >> 4) & 0xf; + opc2 = 0; + rt2 = (insn >> 16) & 0xf; + } else { + crn = (insn >> 16) & 0xf; + opc1 = (insn >> 21) & 7; + opc2 = (insn >> 5) & 7; + rt2 = 0; + } + isread = (insn >> 20) & 1; + rt = (insn >> 12) & 0xf; + + ri = get_arm_cp_reginfo(cpu, + ENCODE_CP_REG(cpnum, is64, crn, crm, opc1, opc2)); + if (ri) { + /* Check access permissions */ + if (!cp_access_ok(env, ri, isread)) { + return 1; + } + + /* Handle special cases first */ + switch (ri->type & ~(ARM_CP_FLAG_MASK & ~ARM_CP_SPECIAL)) { + case ARM_CP_NOP: + return 0; + case ARM_CP_WFI: + if (isread) { + return 1; + } + gen_set_pc_im(s->pc); + s->is_jmp = DISAS_WFI; + break; + default: + break; + } + + if (isread) { + /* Read */ + if (is64) { + TCGv_i64 tmp64; + TCGv_i32 tmp; + if (ri->type & ARM_CP_CONST) { + tmp64 = tcg_const_i64(ri->resetvalue); + } else if (ri->readfn) { + TCGv_ptr tmpptr; + gen_set_pc_im(s->pc); + tmp64 = tcg_temp_new_i64(); + tmpptr = tcg_const_ptr(ri); + gen_helper_get_cp_reg64(tmp64, cpu_env, tmpptr); + tcg_temp_free_ptr(tmpptr); + } else { + tmp64 = tcg_temp_new_i64(); + tcg_gen_ld_i64(tmp64, cpu_env, ri->fieldoffset); + } + tmp = tcg_temp_new_i32(); + tcg_gen_trunc_i64_i32(tmp, tmp64); + store_reg(s, rt, tmp); + tcg_gen_shri_i64(tmp64, tmp64, 32); + tcg_gen_trunc_i64_i32(tmp, tmp64); + store_reg(s, rt2, tmp); + } else { + TCGv tmp; + if (ri->type & ARM_CP_CONST) { + tmp = tcg_const_i32(ri->resetvalue); + } else if (ri->readfn) { + TCGv_ptr tmpptr; + gen_set_pc_im(s->pc); + tmp = tcg_temp_new_i32(); + tmpptr = tcg_const_ptr(ri); + gen_helper_get_cp_reg(tmp, cpu_env, tmpptr); + tcg_temp_free_ptr(tmpptr); + } else { + tmp = load_cpu_offset(ri->fieldoffset); + } + if (rt == 15) { + /* Destination register of r15 for 32 bit loads sets + * the condition codes from the high 4 bits of the value + */ + gen_set_nzcv(tmp); + tcg_temp_free_i32(tmp); + } else { + store_reg(s, rt, tmp); + } + } + } else { + /* Write */ + if (ri->type & ARM_CP_CONST) { + /* If not forbidden by access permissions, treat as WI */ + return 0; + } + + if (is64) { + TCGv tmplo, tmphi; + TCGv_i64 tmp64 = tcg_temp_new_i64(); + tmplo = load_reg(s, rt); + tmphi = load_reg(s, rt2); + tcg_gen_concat_i32_i64(tmp64, tmplo, tmphi); + tcg_temp_free_i32(tmplo); + tcg_temp_free_i32(tmphi); + if (ri->writefn) { + TCGv_ptr tmpptr = tcg_const_ptr(ri); + gen_set_pc_im(s->pc); + gen_helper_set_cp_reg64(cpu_env, tmpptr, tmp64); + tcg_temp_free_ptr(tmpptr); + } else { + tcg_gen_st_i64(tmp64, cpu_env, ri->fieldoffset); + } + tcg_temp_free_i64(tmp64); + } else { + if (ri->writefn) { + TCGv tmp; + TCGv_ptr tmpptr; + gen_set_pc_im(s->pc); + tmp = load_reg(s, rt); + tmpptr = tcg_const_ptr(ri); + gen_helper_set_cp_reg(cpu_env, tmpptr, tmp); + tcg_temp_free_ptr(tmpptr); + tcg_temp_free_i32(tmp); + } else { + TCGv tmp = load_reg(s, rt); + store_cpu_offset(tmp, ri->fieldoffset); + } + } + /* We default to ending the TB on a coprocessor register write, + * but allow this to be suppressed by the register definition + * (usually only necessary to work around guest bugs). + */ + if (!(ri->type & ARM_CP_SUPPRESS_TB_END)) { + gen_lookup_tb(s); + } + } + return 0; + } + + /* Fallback code: handle coprocessor registers not yet converted + * to ARMCPRegInfo. + */ + switch (cpnum) { case 14: /* Coprocessors 7-15 are architecturally reserved by ARM. Unfortunately Intel decided to ignore this. */ -- cgit v1.2.3 From dc2a9045cff0f0c0bb1f58bf82473afb1e9f1c6a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jun 2012 11:57:07 +0000 Subject: hw/pxa2xx: Convert cp14 perf registers to new scheme Convert the PXA2xx cp14 perf registers from old-style coprocessor hooks to the new scheme. Signed-off-by: Peter Maydell --- hw/pxa2xx.c | 142 ++++++++++++++++++++++++++---------------------------------- 1 file changed, 61 insertions(+), 81 deletions(-) diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index 7958d14003..2ab5a4ce88 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -324,80 +324,11 @@ static void pxa2xx_clkpwr_write(void *opaque, int op2, int reg, int crm, } } -/* Performace Monitoring Registers */ -#define CPPMNC 0 /* Performance Monitor Control register */ -#define CPCCNT 1 /* Clock Counter register */ -#define CPINTEN 4 /* Interrupt Enable register */ -#define CPFLAG 5 /* Overflow Flag register */ -#define CPEVTSEL 8 /* Event Selection register */ - -#define CPPMN0 0 /* Performance Count register 0 */ -#define CPPMN1 1 /* Performance Count register 1 */ -#define CPPMN2 2 /* Performance Count register 2 */ -#define CPPMN3 3 /* Performance Count register 3 */ - -static uint32_t pxa2xx_perf_read(void *opaque, int op2, int reg, int crm) -{ - PXA2xxState *s = (PXA2xxState *) opaque; - - switch (reg) { - case CPPMNC: - return s->pmnc; - case CPCCNT: - if (s->pmnc & 1) - return qemu_get_clock_ns(vm_clock); - else - return 0; - case CPINTEN: - case CPFLAG: - case CPEVTSEL: - return 0; - - default: - printf("%s: Bad register 0x%x\n", __FUNCTION__, reg); - break; - } - return 0; -} - -static void pxa2xx_perf_write(void *opaque, int op2, int reg, int crm, - uint32_t value) -{ - PXA2xxState *s = (PXA2xxState *) opaque; - - switch (reg) { - case CPPMNC: - s->pmnc = value; - break; - - case CPCCNT: - case CPINTEN: - case CPFLAG: - case CPEVTSEL: - break; - - default: - printf("%s: Bad register 0x%x\n", __FUNCTION__, reg); - break; - } -} - static uint32_t pxa2xx_cp14_read(void *opaque, int op2, int reg, int crm) { switch (crm) { case 0: return pxa2xx_clkpwr_read(opaque, op2, reg, crm); - case 1: - return pxa2xx_perf_read(opaque, op2, reg, crm); - case 2: - switch (reg) { - case CPPMN0: - case CPPMN1: - case CPPMN2: - case CPPMN3: - return 0; - } - /* Fall through */ default: printf("%s: Bad register 0x%x\n", __FUNCTION__, reg); break; @@ -412,24 +343,71 @@ static void pxa2xx_cp14_write(void *opaque, int op2, int reg, int crm, case 0: pxa2xx_clkpwr_write(opaque, op2, reg, crm, value); break; - case 1: - pxa2xx_perf_write(opaque, op2, reg, crm, value); - break; - case 2: - switch (reg) { - case CPPMN0: - case CPPMN1: - case CPPMN2: - case CPPMN3: - return; - } - /* Fall through */ default: printf("%s: Bad register 0x%x\n", __FUNCTION__, reg); break; } } +static int pxa2xx_cppmnc_read(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t *value) +{ + PXA2xxState *s = (PXA2xxState *)ri->opaque; + *value = s->pmnc; + return 0; +} + +static int pxa2xx_cppmnc_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + PXA2xxState *s = (PXA2xxState *)ri->opaque; + s->pmnc = value; + return 0; +} + +static int pxa2xx_cpccnt_read(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t *value) +{ + PXA2xxState *s = (PXA2xxState *)ri->opaque; + if (s->pmnc & 1) { + *value = qemu_get_clock_ns(vm_clock); + } else { + *value = 0; + } + return 0; +} + +static const ARMCPRegInfo pxa_cp_reginfo[] = { + /* cp14 crn==1: perf registers */ + { .name = "CPPMNC", .cp = 14, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, + .readfn = pxa2xx_cppmnc_read, .writefn = pxa2xx_cppmnc_write }, + { .name = "CPCCNT", .cp = 14, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, + .readfn = pxa2xx_cpccnt_read, .writefn = arm_cp_write_ignore }, + { .name = "CPINTEN", .cp = 14, .crn = 1, .crm = 4, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CPFLAG", .cp = 14, .crn = 1, .crm = 5, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CPEVTSEL", .cp = 14, .crn = 1, .crm = 8, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + /* cp14 crn==2: performance count registers */ + { .name = "CPPMN0", .cp = 14, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CPPMN1", .cp = 14, .crn = 2, .crm = 1, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CPPMN2", .cp = 14, .crn = 2, .crm = 2, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CPPMN3", .cp = 14, .crn = 2, .crm = 3, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + REGINFO_SENTINEL +}; + +static void pxa2xx_setup_cp14(PXA2xxState *s) +{ + define_arm_cp_regs_with_opaque(s->cpu, pxa_cp_reginfo, s); +} + #define MDCNFG 0x00 /* SDRAM Configuration register */ #define MDREFR 0x04 /* SDRAM Refresh Control register */ #define MSC0 0x08 /* Static Memory Control register 0 */ @@ -2134,6 +2112,7 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space, vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s); cpu_arm_set_cp_io(&s->cpu->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s); + pxa2xx_setup_cp14(s); s->mm_base = 0x48000000; s->mm_regs[MDMRS >> 2] = 0x00020002; @@ -2265,6 +2244,7 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size) vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s); cpu_arm_set_cp_io(&s->cpu->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s); + pxa2xx_setup_cp14(s); s->mm_base = 0x48000000; s->mm_regs[MDMRS >> 2] = 0x00020002; -- cgit v1.2.3 From e2f8a44d0d425a22cca5855702f534536f5e8c90 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jun 2012 11:57:07 +0000 Subject: hw/pxa2xx.c: Convert CLKCFG and PWRMODE cp14 regs Convert the PXA2xx CLKCFG and PWRMODE cp14 registers to the new arm_cp_reginfo scheme. Signed-off-by: Peter Maydell --- hw/pxa2xx.c | 171 +++++++++++++++++++++++++----------------------------------- 1 file changed, 71 insertions(+), 100 deletions(-) diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index 2ab5a4ce88..d5f1420ed9 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -224,131 +224,96 @@ static const VMStateDescription vmstate_pxa2xx_cm = { } }; -static uint32_t pxa2xx_clkpwr_read(void *opaque, int op2, int reg, int crm) +static int pxa2xx_clkcfg_read(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t *value) { - PXA2xxState *s = (PXA2xxState *) opaque; - - switch (reg) { - case 6: /* Clock Configuration register */ - return s->clkcfg; - - case 7: /* Power Mode register */ - return 0; + PXA2xxState *s = (PXA2xxState *)ri->opaque; + *value = s->clkcfg; + return 0; +} - default: - printf("%s: Bad register 0x%x\n", __FUNCTION__, reg); - break; +static int pxa2xx_clkcfg_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + PXA2xxState *s = (PXA2xxState *)ri->opaque; + s->clkcfg = value & 0xf; + if (value & 2) { + printf("%s: CPU frequency change attempt\n", __func__); } return 0; } -static void pxa2xx_clkpwr_write(void *opaque, int op2, int reg, int crm, - uint32_t value) +static int pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) { - PXA2xxState *s = (PXA2xxState *) opaque; + PXA2xxState *s = (PXA2xxState *)ri->opaque; static const char *pwrmode[8] = { "Normal", "Idle", "Deep-idle", "Standby", "Sleep", "reserved (!)", "reserved (!)", "Deep-sleep", }; - switch (reg) { - case 6: /* Clock Configuration register */ - s->clkcfg = value & 0xf; - if (value & 2) - printf("%s: CPU frequency change attempt\n", __FUNCTION__); + if (value & 8) { + printf("%s: CPU voltage change attempt\n", __func__); + } + switch (value & 7) { + case 0: + /* Do nothing */ break; - case 7: /* Power Mode register */ - if (value & 8) - printf("%s: CPU voltage change attempt\n", __FUNCTION__); - switch (value & 7) { - case 0: - /* Do nothing */ - break; - - case 1: - /* Idle */ - if (!(s->cm_regs[CCCR >> 2] & (1 << 31))) { /* CPDIS */ - cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HALT); - break; - } - /* Fall through. */ - - case 2: - /* Deep-Idle */ + case 1: + /* Idle */ + if (!(s->cm_regs[CCCR >> 2] & (1 << 31))) { /* CPDIS */ cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HALT); - s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */ - goto message; - - case 3: - s->cpu->env.uncached_cpsr = - ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I; - s->cpu->env.cp15.c1_sys = 0; - s->cpu->env.cp15.c1_coproc = 0; - s->cpu->env.cp15.c2_base0 = 0; - s->cpu->env.cp15.c3 = 0; - s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */ - s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */ - - /* - * The scratch-pad register is almost universally used - * for storing the return address on suspend. For the - * lack of a resuming bootloader, perform a jump - * directly to that address. - */ - memset(s->cpu->env.regs, 0, 4 * 15); - s->cpu->env.regs[15] = s->pm_regs[PSPR >> 2]; + break; + } + /* Fall through. */ + + case 2: + /* Deep-Idle */ + cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HALT); + s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */ + goto message; + + case 3: + s->cpu->env.uncached_cpsr = + ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I; + s->cpu->env.cp15.c1_sys = 0; + s->cpu->env.cp15.c1_coproc = 0; + s->cpu->env.cp15.c2_base0 = 0; + s->cpu->env.cp15.c3 = 0; + s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */ + s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */ + + /* + * The scratch-pad register is almost universally used + * for storing the return address on suspend. For the + * lack of a resuming bootloader, perform a jump + * directly to that address. + */ + memset(s->cpu->env.regs, 0, 4 * 15); + s->cpu->env.regs[15] = s->pm_regs[PSPR >> 2]; #if 0 - buffer = 0xe59ff000; /* ldr pc, [pc, #0] */ - cpu_physical_memory_write(0, &buffer, 4); - buffer = s->pm_regs[PSPR >> 2]; - cpu_physical_memory_write(8, &buffer, 4); + buffer = 0xe59ff000; /* ldr pc, [pc, #0] */ + cpu_physical_memory_write(0, &buffer, 4); + buffer = s->pm_regs[PSPR >> 2]; + cpu_physical_memory_write(8, &buffer, 4); #endif - /* Suspend */ - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT); - - goto message; + /* Suspend */ + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT); - default: - message: - printf("%s: machine entered %s mode\n", __FUNCTION__, - pwrmode[value & 7]); - } - break; + goto message; default: - printf("%s: Bad register 0x%x\n", __FUNCTION__, reg); - break; + message: + printf("%s: machine entered %s mode\n", __func__, + pwrmode[value & 7]); } -} -static uint32_t pxa2xx_cp14_read(void *opaque, int op2, int reg, int crm) -{ - switch (crm) { - case 0: - return pxa2xx_clkpwr_read(opaque, op2, reg, crm); - default: - printf("%s: Bad register 0x%x\n", __FUNCTION__, reg); - break; - } return 0; } -static void pxa2xx_cp14_write(void *opaque, int op2, int reg, int crm, - uint32_t value) -{ - switch (crm) { - case 0: - pxa2xx_clkpwr_write(opaque, op2, reg, crm, value); - break; - default: - printf("%s: Bad register 0x%x\n", __FUNCTION__, reg); - break; - } -} - static int pxa2xx_cppmnc_read(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t *value) { @@ -400,6 +365,14 @@ static const ARMCPRegInfo pxa_cp_reginfo[] = { .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, { .name = "CPPMN3", .cp = 14, .crn = 2, .crm = 3, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + /* cp14 crn==6: CLKCFG */ + { .name = "CLKCFG", .cp = 14, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, + .readfn = pxa2xx_clkcfg_read, .writefn = pxa2xx_clkcfg_write }, + /* cp14 crn==7: PWRMODE */ + { .name = "PWRMODE", .cp = 14, .crn = 7, .crm = 0, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, + .readfn = arm_cp_read_zero, .writefn = pxa2xx_pwrmode_write }, REGINFO_SENTINEL }; @@ -2111,7 +2084,6 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space, memory_region_add_subregion(address_space, s->cm_base, &s->cm_iomem); vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s); - cpu_arm_set_cp_io(&s->cpu->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s); pxa2xx_setup_cp14(s); s->mm_base = 0x48000000; @@ -2243,7 +2215,6 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size) memory_region_add_subregion(address_space, s->cm_base, &s->cm_iomem); vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s); - cpu_arm_set_cp_io(&s->cpu->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s); pxa2xx_setup_cp14(s); s->mm_base = 0x48000000; -- cgit v1.2.3 From 9ee703b0965fb8dc52b22a3511fa67a1c120d52b Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jun 2012 11:57:08 +0000 Subject: hw/pxa2xx_pic: Convert coprocessor registers to new scheme Convert the coprocessor access functions for the pxa2xx PIC to the arm_cp_reginfo scheme. Signed-off-by: Peter Maydell --- hw/pxa2xx_pic.c | 53 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/hw/pxa2xx_pic.c b/hw/pxa2xx_pic.c index c560133930..e1e8830ff0 100644 --- a/hw/pxa2xx_pic.c +++ b/hw/pxa2xx_pic.c @@ -209,33 +209,42 @@ static const int pxa2xx_cp_reg_map[0x10] = { [0xa] = ICPR2, }; -static uint32_t pxa2xx_pic_cp_read(void *opaque, int op2, int reg, int crm) +static int pxa2xx_pic_cp_read(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t *value) { - target_phys_addr_t offset; - - if (pxa2xx_cp_reg_map[reg] == -1) { - printf("%s: Bad register 0x%x\n", __FUNCTION__, reg); - return 0; - } - - offset = pxa2xx_cp_reg_map[reg]; - return pxa2xx_pic_mem_read(opaque, offset, 4); + int offset = pxa2xx_cp_reg_map[ri->crn]; + *value = pxa2xx_pic_mem_read(ri->opaque, offset, 4); + return 0; } -static void pxa2xx_pic_cp_write(void *opaque, int op2, int reg, int crm, - uint32_t value) +static int pxa2xx_pic_cp_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) { - target_phys_addr_t offset; - - if (pxa2xx_cp_reg_map[reg] == -1) { - printf("%s: Bad register 0x%x\n", __FUNCTION__, reg); - return; - } - - offset = pxa2xx_cp_reg_map[reg]; - pxa2xx_pic_mem_write(opaque, offset, value, 4); + int offset = pxa2xx_cp_reg_map[ri->crn]; + pxa2xx_pic_mem_write(ri->opaque, offset, value, 4); + return 0; } +#define REGINFO_FOR_PIC_CP(NAME, CRN) \ + { .name = NAME, .cp = 6, .crn = CRN, .crm = 0, .opc1 = 0, .opc2 = 0, \ + .access = PL1_RW, \ + .readfn = pxa2xx_pic_cp_read, .writefn = pxa2xx_pic_cp_write } + +static const ARMCPRegInfo pxa_pic_cp_reginfo[] = { + REGINFO_FOR_PIC_CP("ICIP", 0), + REGINFO_FOR_PIC_CP("ICMR", 1), + REGINFO_FOR_PIC_CP("ICLR", 2), + REGINFO_FOR_PIC_CP("ICFP", 3), + REGINFO_FOR_PIC_CP("ICPR", 4), + REGINFO_FOR_PIC_CP("ICHP", 5), + REGINFO_FOR_PIC_CP("ICIP2", 6), + REGINFO_FOR_PIC_CP("ICMR2", 7), + REGINFO_FOR_PIC_CP("ICLR2", 8), + REGINFO_FOR_PIC_CP("ICFP2", 9), + REGINFO_FOR_PIC_CP("ICPR2", 0xa), + REGINFO_SENTINEL +}; + static const MemoryRegionOps pxa2xx_pic_ops = { .read = pxa2xx_pic_mem_read, .write = pxa2xx_pic_mem_write, @@ -274,7 +283,7 @@ DeviceState *pxa2xx_pic_init(target_phys_addr_t base, ARMCPU *cpu) sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); /* Enable IC coprocessor access. */ - cpu_arm_set_cp_io(env, 6, pxa2xx_pic_cp_read, pxa2xx_pic_cp_write, s); + define_arm_cp_regs_with_opaque(arm_env_get_cpu(env), pxa_pic_cp_reginfo, s); return dev; } -- cgit v1.2.3 From e8070a23a8f9f6fa28ac1dcb4399c11492f18b10 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jun 2012 11:57:08 +0000 Subject: target-arm: Remove old cpu_arm_set_cp_io infrastructure All the users of cpu_arm_set_cp_io have been converted, so we can remove it and the infrastructure it used. Signed-off-by: Peter Maydell --- target-arm/cpu.h | 10 ---------- target-arm/helper.c | 54 -------------------------------------------------- target-arm/helper.h | 3 --- target-arm/translate.c | 41 +------------------------------------- 4 files changed, 1 insertion(+), 107 deletions(-) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 6c7d3e72e0..a61cb07d4c 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -228,12 +228,6 @@ typedef struct CPUARMState { /* Internal CPU feature flags. */ uint32_t features; - /* Coprocessor IO used by peripherals */ - struct { - ARMReadCPFunc *cp_read; - ARMWriteCPFunc *cp_write; - void *opaque; - } cp[15]; void *nvic; const struct arm_boot_info *boot_info; } CPUARMState; @@ -406,10 +400,6 @@ void armv7m_nvic_set_pending(void *opaque, int irq); int armv7m_nvic_acknowledge_irq(void *opaque); void armv7m_nvic_complete_irq(void *opaque, int irq); -void cpu_arm_set_cp_io(CPUARMState *env, int cpnum, - ARMReadCPFunc *cp_read, ARMWriteCPFunc *cp_write, - void *opaque); - /* Interface for defining coprocessor registers. * Registers are defined in tables of arm_cp_reginfo structs * which are passed to define_arm_cp_regs(). diff --git a/target-arm/helper.c b/target-arm/helper.c index 70324234ec..57bb78b7bd 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -386,21 +386,6 @@ int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address, int rw, return 1; } -/* These should probably raise undefined insn exceptions. */ -void HELPER(set_cp)(CPUARMState *env, uint32_t insn, uint32_t val) -{ - int op1 = (insn >> 8) & 0xf; - cpu_abort(env, "cp%i insn %08x\n", op1, insn); - return; -} - -uint32_t HELPER(get_cp)(CPUARMState *env, uint32_t insn) -{ - int op1 = (insn >> 8) & 0xf; - cpu_abort(env, "cp%i insn %08x\n", op1, insn); - return 0; -} - void HELPER(set_cp15)(CPUARMState *env, uint32_t insn, uint32_t val) { cpu_abort(env, "cp15 insn %08x\n", insn); @@ -1137,31 +1122,6 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUARMState *env, target_ulong addr) return phys_addr; } -void HELPER(set_cp)(CPUARMState *env, uint32_t insn, uint32_t val) -{ - int cp_num = (insn >> 8) & 0xf; - int cp_info = (insn >> 5) & 7; - int src = (insn >> 16) & 0xf; - int operand = insn & 0xf; - - if (env->cp[cp_num].cp_write) - env->cp[cp_num].cp_write(env->cp[cp_num].opaque, - cp_info, src, operand, val); -} - -uint32_t HELPER(get_cp)(CPUARMState *env, uint32_t insn) -{ - int cp_num = (insn >> 8) & 0xf; - int cp_info = (insn >> 5) & 7; - int dest = (insn >> 16) & 0xf; - int operand = insn & 0xf; - - if (env->cp[cp_num].cp_read) - return env->cp[cp_num].cp_read(env->cp[cp_num].opaque, - cp_info, dest, operand); - return 0; -} - /* Return basic MPU access permission bits. */ static uint32_t simple_mpu_ap_bits(uint32_t val) { @@ -2125,20 +2085,6 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t reg, uint32_t val) } } -void cpu_arm_set_cp_io(CPUARMState *env, int cpnum, - ARMReadCPFunc *cp_read, ARMWriteCPFunc *cp_write, - void *opaque) -{ - if (cpnum < 0 || cpnum > 14) { - cpu_abort(env, "Bad coprocessor number: %i\n", cpnum); - return; - } - - env->cp[cpnum].cp_read = cp_read; - env->cp[cpnum].cp_write = cp_write; - env->cp[cpnum].opaque = opaque; -} - #endif /* Note that signed overflow is undefined in C. The following routines are diff --git a/target-arm/helper.h b/target-arm/helper.h index b6cefed206..bb6b85da72 100644 --- a/target-arm/helper.h +++ b/target-arm/helper.h @@ -62,9 +62,6 @@ DEF_HELPER_2(v7m_mrs, i32, env, i32) DEF_HELPER_3(set_cp15, void, env, i32, i32) DEF_HELPER_2(get_cp15, i32, env, i32) -DEF_HELPER_3(set_cp, void, env, i32, i32) -DEF_HELPER_2(get_cp, i32, env, i32) - DEF_HELPER_3(set_cp_reg, void, env, ptr, i32) DEF_HELPER_2(get_cp_reg, i32, env, ptr) DEF_HELPER_3(set_cp_reg64, void, env, ptr, i64) diff --git a/target-arm/translate.c b/target-arm/translate.c index d7edda758e..75e464d1b1 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -2439,39 +2439,6 @@ static int disas_dsp_insn(CPUARMState *env, DisasContext *s, uint32_t insn) return 1; } -/* Disassemble system coprocessor instruction. Return nonzero if - instruction is not defined. */ -static int disas_cp_insn(CPUARMState *env, DisasContext *s, uint32_t insn) -{ - TCGv tmp, tmp2; - uint32_t rd = (insn >> 12) & 0xf; - uint32_t cp = (insn >> 8) & 0xf; - if (IS_USER(s)) { - return 1; - } - - if (insn & ARM_CP_RW_BIT) { - if (!env->cp[cp].cp_read) - return 1; - gen_set_pc_im(s->pc); - tmp = tcg_temp_new_i32(); - tmp2 = tcg_const_i32(insn); - gen_helper_get_cp(tmp, cpu_env, tmp2); - tcg_temp_free(tmp2); - store_reg(s, rd, tmp); - } else { - if (!env->cp[cp].cp_write) - return 1; - gen_set_pc_im(s->pc); - tmp = load_reg(s, rd); - tmp2 = tcg_const_i32(insn); - gen_helper_set_cp(cpu_env, tmp2, tmp); - tcg_temp_free(tmp2); - tcg_temp_free_i32(tmp); - } - return 0; -} - static int cp15_user_ok(CPUARMState *env, uint32_t insn) { int cpn = (insn >> 16) & 0xf; @@ -6653,10 +6620,6 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn) */ switch (cpnum) { case 14: - /* Coprocessors 7-15 are architecturally reserved by ARM. - Unfortunately Intel decided to ignore this. */ - if (arm_feature(env, ARM_FEATURE_XSCALE)) - goto board; if (insn & (1 << 20)) return disas_cp14_read(env, s, insn); else @@ -6664,9 +6627,7 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn) case 15: return disas_cp15_insn (env, s, insn); default: - board: - /* Unknown coprocessor. See if the board has hooked it. */ - return disas_cp_insn (env, s, insn); + return 1; } } -- cgit v1.2.3 From 2ceb98c0079a68078947c222111238c7c7ae89b5 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jun 2012 11:57:09 +0000 Subject: target-arm: Add register_cp_regs_for_features() Add new function register_cp_regs_for_features() as a place to register coprocessor registers dependent on feature flags. Signed-off-by: Peter Maydell --- target-arm/cpu-qom.h | 1 + target-arm/cpu.c | 2 ++ target-arm/helper.c | 11 +++++++++++ 3 files changed, 14 insertions(+) diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h index 848ac2ffdf..4ccfc897c2 100644 --- a/target-arm/cpu-qom.h +++ b/target-arm/cpu-qom.h @@ -107,5 +107,6 @@ static inline ARMCPU *arm_env_get_cpu(CPUARMState *env) #define ENV_GET_CPU(e) CPU(arm_env_get_cpu(e)) void arm_cpu_realize(ARMCPU *cpu); +void register_cp_regs_for_features(ARMCPU *cpu); #endif diff --git a/target-arm/cpu.c b/target-arm/cpu.c index 6456a3dfa8..1aff266b6b 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -216,6 +216,8 @@ void arm_cpu_realize(ARMCPU *cpu) if (arm_feature(env, ARM_FEATURE_VFP3)) { set_feature(env, ARM_FEATURE_VFP); } + + register_cp_regs_for_features(cpu); } /* CPU models */ diff --git a/target-arm/helper.c b/target-arm/helper.c index 57bb78b7bd..f7c9a3a1e8 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -56,6 +56,17 @@ static int vfp_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg) return 0; } +void register_cp_regs_for_features(ARMCPU *cpu) +{ + /* Register all the coprocessor registers based on feature bits */ + CPUARMState *env = &cpu->env; + if (arm_feature(env, ARM_FEATURE_M)) { + /* M profile has no coprocessor registers */ + return; + } + +} + ARMCPU *cpu_arm_init(const char *cpu_model) { ARMCPU *cpu; -- cgit v1.2.3 From e9aa6c21483bc50767132c305284cd5446001df7 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jun 2012 11:57:09 +0000 Subject: target-arm: Convert debug registers to cp_reginfo Convert the cp14 debug registers (DBGDIDR, DBGDRAR, DBGDSAR) to the cp_reginfo scheme. Signed-off-by: Peter Maydell --- target-arm/helper.c | 25 +++++++++++++++++++++++++ target-arm/translate.c | 28 ---------------------------- 2 files changed, 25 insertions(+), 28 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index f7c9a3a1e8..a750637b1d 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -56,6 +56,27 @@ static int vfp_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg) return 0; } +static const ARMCPRegInfo cp_reginfo[] = { + /* DBGDIDR: just RAZ. In particular this means the "debug architecture + * version" bits will read as a reserved value, which should cause + * Linux to not try to use the debug hardware. + */ + { .name = "DBGDIDR", .cp = 14, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 0, + .access = PL0_R, .type = ARM_CP_CONST, .resetvalue = 0 }, + REGINFO_SENTINEL +}; + +static const ARMCPRegInfo v7_cp_reginfo[] = { + /* DBGDRAR, DBGDSAR: always RAZ since we don't implement memory mapped + * debug components + */ + { .name = "DBGDRAR", .cp = 14, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 0, + .access = PL0_R, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "DBGDRAR", .cp = 14, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 0, + .access = PL0_R, .type = ARM_CP_CONST, .resetvalue = 0 }, + REGINFO_SENTINEL +}; + void register_cp_regs_for_features(ARMCPU *cpu) { /* Register all the coprocessor registers based on feature bits */ @@ -65,6 +86,10 @@ void register_cp_regs_for_features(ARMCPU *cpu) return; } + define_arm_cp_regs(cpu, cp_reginfo); + if (arm_feature(env, ARM_FEATURE_V7)) { + define_arm_cp_regs(cpu, v7_cp_reginfo); + } } ARMCPU *cpu_arm_init(const char *cpu_model) diff --git a/target-arm/translate.c b/target-arm/translate.c index 75e464d1b1..d9fa431571 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -6364,34 +6364,6 @@ static int disas_cp14_read(CPUARMState * env, DisasContext *s, uint32_t insn) int rt = (insn >> 12) & 0xf; TCGv tmp; - /* Minimal set of debug registers, since we don't support debug */ - if (op1 == 0 && crn == 0 && op2 == 0) { - switch (crm) { - case 0: - /* DBGDIDR: just RAZ. In particular this means the - * "debug architecture version" bits will read as - * a reserved value, which should cause Linux to - * not try to use the debug hardware. - */ - tmp = tcg_const_i32(0); - store_reg(s, rt, tmp); - return 0; - case 1: - case 2: - /* DBGDRAR and DBGDSAR: v7 only. Always RAZ since we - * don't implement memory mapped debug components - */ - if (ENABLE_ARCH_7) { - tmp = tcg_const_i32(0); - store_reg(s, rt, tmp); - return 0; - } - break; - default: - break; - } - } - if (arm_feature(env, ARM_FEATURE_THUMB2EE)) { if (op1 == 6 && crn == 0 && crm == 0 && op2 == 0) { /* TEECR */ -- cgit v1.2.3 From c326b9796fe1f8661310ff9b9be4e38148b8baa4 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jun 2012 11:57:10 +0000 Subject: target-arm: Convert TEECR, TEEHBR to new scheme Convert the THUMB2EE cp14 registers TEECR and TEEHBR to use arm_cp_reginfo. Signed-off-by: Peter Maydell --- target-arm/helper.c | 54 ++++++++++++++++++++++++++++++++++------- target-arm/helper.h | 2 -- target-arm/translate.c | 66 -------------------------------------------------- 3 files changed, 45 insertions(+), 77 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index a750637b1d..c003fe0fd1 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -77,6 +77,48 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { REGINFO_SENTINEL }; +static int teecr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) +{ + value &= 1; + env->teecr = value; + return 0; +} + +static int teehbr_read(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t *value) +{ + /* This is a helper function because the user access rights + * depend on the value of the TEECR. + */ + if (arm_current_pl(env) == 0 && (env->teecr & 1)) { + return EXCP_UDEF; + } + *value = env->teehbr; + return 0; +} + +static int teehbr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + if (arm_current_pl(env) == 0 && (env->teecr & 1)) { + return EXCP_UDEF; + } + env->teehbr = value; + return 0; +} + +static const ARMCPRegInfo t2ee_cp_reginfo[] = { + { .name = "TEECR", .cp = 14, .crn = 0, .crm = 0, .opc1 = 6, .opc2 = 0, + .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, teecr), + .resetvalue = 0, + .writefn = teecr_write }, + { .name = "TEEHBR", .cp = 14, .crn = 1, .crm = 0, .opc1 = 6, .opc2 = 0, + .access = PL0_RW, .fieldoffset = offsetof(CPUARMState, teehbr), + .resetvalue = 0, + .readfn = teehbr_read, .writefn = teehbr_write }, + REGINFO_SENTINEL +}; + void register_cp_regs_for_features(ARMCPU *cpu) { /* Register all the coprocessor registers based on feature bits */ @@ -90,6 +132,9 @@ void register_cp_regs_for_features(ARMCPU *cpu) if (arm_feature(env, ARM_FEATURE_V7)) { define_arm_cp_regs(cpu, v7_cp_reginfo); } + if (arm_feature(env, ARM_FEATURE_THUMB2EE)) { + define_arm_cp_regs(cpu, t2ee_cp_reginfo); + } } ARMCPU *cpu_arm_init(const char *cpu_model) @@ -2951,12 +2996,3 @@ float64 VFP_HELPER(muladd, d)(float64 a, float64 b, float64 c, void *fpstp) float_status *fpst = fpstp; return float64_muladd(a, b, c, 0, fpst); } - -void HELPER(set_teecr)(CPUARMState *env, uint32_t val) -{ - val &= 1; - if (env->teecr != val) { - env->teecr = val; - tb_flush(env); - } -} diff --git a/target-arm/helper.h b/target-arm/helper.h index bb6b85da72..a0034ae630 100644 --- a/target-arm/helper.h +++ b/target-arm/helper.h @@ -461,8 +461,6 @@ DEF_HELPER_3(iwmmxt_muladdsl, i64, i64, i32, i32) DEF_HELPER_3(iwmmxt_muladdsw, i64, i64, i32, i32) DEF_HELPER_3(iwmmxt_muladdswl, i64, i64, i32, i32) -DEF_HELPER_2(set_teecr, void, env, i32) - DEF_HELPER_3(neon_unzip8, void, env, i32, i32) DEF_HELPER_3(neon_unzip16, void, env, i32, i32) DEF_HELPER_3(neon_qunzip8, void, env, i32, i32) diff --git a/target-arm/translate.c b/target-arm/translate.c index d9fa431571..ba1bb945f3 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -6355,67 +6355,6 @@ static int disas_neon_data_insn(CPUARMState * env, DisasContext *s, uint32_t ins return 0; } -static int disas_cp14_read(CPUARMState * env, DisasContext *s, uint32_t insn) -{ - int crn = (insn >> 16) & 0xf; - int crm = insn & 0xf; - int op1 = (insn >> 21) & 7; - int op2 = (insn >> 5) & 7; - int rt = (insn >> 12) & 0xf; - TCGv tmp; - - if (arm_feature(env, ARM_FEATURE_THUMB2EE)) { - if (op1 == 6 && crn == 0 && crm == 0 && op2 == 0) { - /* TEECR */ - if (IS_USER(s)) - return 1; - tmp = load_cpu_field(teecr); - store_reg(s, rt, tmp); - return 0; - } - if (op1 == 6 && crn == 1 && crm == 0 && op2 == 0) { - /* TEEHBR */ - if (IS_USER(s) && (env->teecr & 1)) - return 1; - tmp = load_cpu_field(teehbr); - store_reg(s, rt, tmp); - return 0; - } - } - return 1; -} - -static int disas_cp14_write(CPUARMState * env, DisasContext *s, uint32_t insn) -{ - int crn = (insn >> 16) & 0xf; - int crm = insn & 0xf; - int op1 = (insn >> 21) & 7; - int op2 = (insn >> 5) & 7; - int rt = (insn >> 12) & 0xf; - TCGv tmp; - - if (arm_feature(env, ARM_FEATURE_THUMB2EE)) { - if (op1 == 6 && crn == 0 && crm == 0 && op2 == 0) { - /* TEECR */ - if (IS_USER(s)) - return 1; - tmp = load_reg(s, rt); - gen_helper_set_teecr(cpu_env, tmp); - tcg_temp_free_i32(tmp); - return 0; - } - if (op1 == 6 && crn == 1 && crm == 0 && op2 == 0) { - /* TEEHBR */ - if (IS_USER(s) && (env->teecr & 1)) - return 1; - tmp = load_reg(s, rt); - store_cpu_field(tmp, teehbr); - return 0; - } - } - return 1; -} - static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn) { int cpnum, is64, crn, crm, opc1, opc2, isread, rt, rt2; @@ -6591,11 +6530,6 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn) * to ARMCPRegInfo. */ switch (cpnum) { - case 14: - if (insn & (1 << 20)) - return disas_cp14_read(env, s, insn); - else - return disas_cp14_write(env, s, insn); case 15: return disas_cp15_insn (env, s, insn); default: -- cgit v1.2.3 From 7d57f40877675db150d8afbf781de385c3828012 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jun 2012 11:57:11 +0000 Subject: target-arm: Convert WFI/barriers special cases to cp_reginfo Convert the various WFI and barrier instruction special cases to use cp_reginfo infrastructure. Signed-off-by: Peter Maydell --- target-arm/helper.c | 42 +++++++++++++++++++++++++++++++++++++++++ target-arm/translate.c | 51 -------------------------------------------------- 2 files changed, 42 insertions(+), 51 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index c003fe0fd1..c7addea7f6 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -66,6 +66,38 @@ static const ARMCPRegInfo cp_reginfo[] = { REGINFO_SENTINEL }; +static const ARMCPRegInfo not_v6_cp_reginfo[] = { + /* Not all pre-v6 cores implemented this WFI, so this is slightly + * over-broad. + */ + { .name = "WFI_v5", .cp = 15, .crn = 7, .crm = 8, .opc1 = 0, .opc2 = 2, + .access = PL1_W, .type = ARM_CP_WFI }, + REGINFO_SENTINEL +}; + +static const ARMCPRegInfo not_v7_cp_reginfo[] = { + /* Standard v6 WFI (also used in some pre-v6 cores); not in v7 (which + * is UNPREDICTABLE; we choose to NOP as most implementations do). + */ + { .name = "WFI_v6", .cp = 15, .crn = 7, .crm = 0, .opc1 = 0, .opc2 = 4, + .access = PL1_W, .type = ARM_CP_WFI }, + REGINFO_SENTINEL +}; + +static const ARMCPRegInfo v6_cp_reginfo[] = { + /* prefetch by MVA in v6, NOP in v7 */ + { .name = "MVA_prefetch", + .cp = 15, .crn = 7, .crm = 13, .opc1 = 0, .opc2 = 1, + .access = PL1_W, .type = ARM_CP_NOP }, + { .name = "ISB", .cp = 15, .crn = 7, .crm = 5, .opc1 = 0, .opc2 = 4, + .access = PL0_W, .type = ARM_CP_NOP }, + { .name = "ISB", .cp = 15, .crn = 7, .crm = 10, .opc1 = 0, .opc2 = 4, + .access = PL0_W, .type = ARM_CP_NOP }, + { .name = "ISB", .cp = 15, .crn = 7, .crm = 10, .opc1 = 0, .opc2 = 5, + .access = PL0_W, .type = ARM_CP_NOP }, + REGINFO_SENTINEL +}; + static const ARMCPRegInfo v7_cp_reginfo[] = { /* DBGDRAR, DBGDSAR: always RAZ since we don't implement memory mapped * debug components @@ -74,6 +106,9 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { .access = PL0_R, .type = ARM_CP_CONST, .resetvalue = 0 }, { .name = "DBGDRAR", .cp = 14, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 0, .access = PL0_R, .type = ARM_CP_CONST, .resetvalue = 0 }, + /* the old v6 WFI, UNPREDICTABLE in v7 but we choose to NOP */ + { .name = "NOP", .cp = 15, .crn = 7, .crm = 0, .opc1 = 0, .opc2 = 4, + .access = PL1_W, .type = ARM_CP_NOP }, REGINFO_SENTINEL }; @@ -129,8 +164,15 @@ void register_cp_regs_for_features(ARMCPU *cpu) } define_arm_cp_regs(cpu, cp_reginfo); + if (arm_feature(env, ARM_FEATURE_V6)) { + define_arm_cp_regs(cpu, v6_cp_reginfo); + } else { + define_arm_cp_regs(cpu, not_v6_cp_reginfo); + } if (arm_feature(env, ARM_FEATURE_V7)) { define_arm_cp_regs(cpu, v7_cp_reginfo); + } else { + define_arm_cp_regs(cpu, not_v7_cp_reginfo); } if (arm_feature(env, ARM_FEATURE_THUMB2EE)) { define_arm_cp_regs(cpu, t2ee_cp_reginfo); diff --git a/target-arm/translate.c b/target-arm/translate.c index ba1bb945f3..a4429ea0ba 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -2541,57 +2541,6 @@ static int disas_cp15_insn(CPUARMState *env, DisasContext *s, uint32_t insn) /* cdp */ return 1; } - /* We special case a number of cp15 instructions which were used - * for things which are real instructions in ARMv7. This allows - * them to work in linux-user mode which doesn't provide functional - * get_cp15/set_cp15 helpers, and is more efficient anyway. - */ - switch ((insn & 0x0fff0fff)) { - case 0x0e070f90: - /* 0,c7,c0,4: Standard v6 WFI (also used in some pre-v6 cores). - * In v7, this must NOP. - */ - if (IS_USER(s)) { - return 1; - } - if (!arm_feature(env, ARM_FEATURE_V7)) { - /* Wait for interrupt. */ - gen_set_pc_im(s->pc); - s->is_jmp = DISAS_WFI; - } - return 0; - case 0x0e070f58: - /* 0,c7,c8,2: Not all pre-v6 cores implemented this WFI, - * so this is slightly over-broad. - */ - if (!IS_USER(s) && !arm_feature(env, ARM_FEATURE_V6)) { - /* Wait for interrupt. */ - gen_set_pc_im(s->pc); - s->is_jmp = DISAS_WFI; - return 0; - } - /* Otherwise continue to handle via helper function. - * In particular, on v7 and some v6 cores this is one of - * the VA-PA registers. - */ - break; - case 0x0e070f3d: - /* 0,c7,c13,1: prefetch-by-MVA in v6, NOP in v7 */ - if (arm_feature(env, ARM_FEATURE_V6)) { - return IS_USER(s) ? 1 : 0; - } - break; - case 0x0e070f95: /* 0,c7,c5,4 : ISB */ - case 0x0e070f9a: /* 0,c7,c10,4: DSB */ - case 0x0e070fba: /* 0,c7,c10,5: DMB */ - /* Barriers in both v6 and v7 */ - if (arm_feature(env, ARM_FEATURE_V6)) { - return 0; - } - break; - default: - break; - } if (IS_USER(s) && !cp15_user_ok(env, insn)) { return 1; -- cgit v1.2.3 From 4d31c5967979d11c22c69a52beb1a03cab377e4f Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jun 2012 11:57:11 +0000 Subject: target-arm: Convert TLS registers Convert TLS registers to the new cp15 framework Signed-off-by: Peter Maydell --- target-arm/helper.c | 19 +++++++++++++++++ target-arm/translate.c | 58 -------------------------------------------------- 2 files changed, 19 insertions(+), 58 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index c7addea7f6..d4c8a1ca8f 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -154,6 +154,22 @@ static const ARMCPRegInfo t2ee_cp_reginfo[] = { REGINFO_SENTINEL }; +static const ARMCPRegInfo v6k_cp_reginfo[] = { + { .name = "TPIDRURW", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0, .opc2 = 2, + .access = PL0_RW, + .fieldoffset = offsetof(CPUARMState, cp15.c13_tls1), + .resetvalue = 0 }, + { .name = "TPIDRURO", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0, .opc2 = 3, + .access = PL0_R|PL1_W, + .fieldoffset = offsetof(CPUARMState, cp15.c13_tls2), + .resetvalue = 0 }, + { .name = "TPIDRPRW", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0, .opc2 = 4, + .access = PL1_RW, + .fieldoffset = offsetof(CPUARMState, cp15.c13_tls3), + .resetvalue = 0 }, + REGINFO_SENTINEL +}; + void register_cp_regs_for_features(ARMCPU *cpu) { /* Register all the coprocessor registers based on feature bits */ @@ -169,6 +185,9 @@ void register_cp_regs_for_features(ARMCPU *cpu) } else { define_arm_cp_regs(cpu, not_v6_cp_reginfo); } + if (arm_feature(env, ARM_FEATURE_V6K)) { + define_arm_cp_regs(cpu, v6k_cp_reginfo); + } if (arm_feature(env, ARM_FEATURE_V7)) { define_arm_cp_regs(cpu, v7_cp_reginfo); } else { diff --git a/target-arm/translate.c b/target-arm/translate.c index a4429ea0ba..e6b0d8707c 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -2460,64 +2460,9 @@ static int cp15_user_ok(CPUARMState *env, uint32_t insn) } return 0; } - - if (cpn == 13 && cpm == 0) { - /* TLS register. */ - if (op == 2 || (op == 3 && (insn & ARM_CP_RW_BIT))) - return 1; - } return 0; } -static int cp15_tls_load_store(CPUARMState *env, DisasContext *s, uint32_t insn, uint32_t rd) -{ - TCGv tmp; - int cpn = (insn >> 16) & 0xf; - int cpm = insn & 0xf; - int op = ((insn >> 5) & 7) | ((insn >> 18) & 0x38); - - if (!arm_feature(env, ARM_FEATURE_V6K)) - return 0; - - if (!(cpn == 13 && cpm == 0)) - return 0; - - if (insn & ARM_CP_RW_BIT) { - switch (op) { - case 2: - tmp = load_cpu_field(cp15.c13_tls1); - break; - case 3: - tmp = load_cpu_field(cp15.c13_tls2); - break; - case 4: - tmp = load_cpu_field(cp15.c13_tls3); - break; - default: - return 0; - } - store_reg(s, rd, tmp); - - } else { - tmp = load_reg(s, rd); - switch (op) { - case 2: - store_cpu_field(tmp, cp15.c13_tls1); - break; - case 3: - store_cpu_field(tmp, cp15.c13_tls2); - break; - case 4: - store_cpu_field(tmp, cp15.c13_tls3); - break; - default: - tcg_temp_free_i32(tmp); - return 0; - } - } - return 1; -} - /* Disassemble system coprocessor (cp15) instruction. Return nonzero if instruction is not defined. */ static int disas_cp15_insn(CPUARMState *env, DisasContext *s, uint32_t insn) @@ -2548,9 +2493,6 @@ static int disas_cp15_insn(CPUARMState *env, DisasContext *s, uint32_t insn) rd = (insn >> 12) & 0xf; - if (cp15_tls_load_store(env, s, insn, rd)) - return 0; - tmp2 = tcg_const_i32(insn); if (insn & ARM_CP_RW_BIT) { tmp = tcg_temp_new_i32(); -- cgit v1.2.3 From 200ac0ef87d3d076ccd5d738e4d1acb7f7b2879f Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jun 2012 11:57:12 +0000 Subject: target-arm: Convert performance monitor registers Convert the v7 performance monitor cp15 registers to the new scheme. Signed-off-by: Peter Maydell --- target-arm/cpu.c | 4 - target-arm/helper.c | 277 ++++++++++++++++++++++++++++--------------------- target-arm/translate.c | 26 +---- 3 files changed, 158 insertions(+), 149 deletions(-) diff --git a/target-arm/cpu.c b/target-arm/cpu.c index 1aff266b6b..00987870cd 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -132,10 +132,6 @@ static void arm_cpu_reset(CPUState *s) } env->vfp.xregs[ARM_VFP_FPEXC] = 0; env->cp15.c2_base_mask = 0xffffc000u; - /* v7 performance monitor control register: same implementor - * field as main ID register, and we implement no event counters. - */ - env->cp15.c9_pmcr = (cpu->midr & 0xff000000); #endif set_flush_to_zero(1, &env->vfp.standard_fp_status); set_flush_inputs_to_zero(1, &env->vfp.standard_fp_status); diff --git a/target-arm/helper.c b/target-arm/helper.c index d4c8a1ca8f..ebe6a55910 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -98,6 +98,97 @@ static const ARMCPRegInfo v6_cp_reginfo[] = { REGINFO_SENTINEL }; +static int pmreg_read(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t *value) +{ + /* Generic performance monitor register read function for where + * user access may be allowed by PMUSERENR. + */ + if (arm_current_pl(env) == 0 && !env->cp15.c9_pmuserenr) { + return EXCP_UDEF; + } + *value = CPREG_FIELD32(env, ri); + return 0; +} + +static int pmcr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + if (arm_current_pl(env) == 0 && !env->cp15.c9_pmuserenr) { + return EXCP_UDEF; + } + /* only the DP, X, D and E bits are writable */ + env->cp15.c9_pmcr &= ~0x39; + env->cp15.c9_pmcr |= (value & 0x39); + return 0; +} + +static int pmcntenset_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + if (arm_current_pl(env) == 0 && !env->cp15.c9_pmuserenr) { + return EXCP_UDEF; + } + value &= (1 << 31); + env->cp15.c9_pmcnten |= value; + return 0; +} + +static int pmcntenclr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + if (arm_current_pl(env) == 0 && !env->cp15.c9_pmuserenr) { + return EXCP_UDEF; + } + value &= (1 << 31); + env->cp15.c9_pmcnten &= ~value; + return 0; +} + +static int pmovsr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + if (arm_current_pl(env) == 0 && !env->cp15.c9_pmuserenr) { + return EXCP_UDEF; + } + env->cp15.c9_pmovsr &= ~value; + return 0; +} + +static int pmxevtyper_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + if (arm_current_pl(env) == 0 && !env->cp15.c9_pmuserenr) { + return EXCP_UDEF; + } + env->cp15.c9_pmxevtyper = value & 0xff; + return 0; +} + +static int pmuserenr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + env->cp15.c9_pmuserenr = value & 1; + return 0; +} + +static int pmintenset_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + /* We have no event counters so only the C bit can be changed */ + value &= (1 << 31); + env->cp15.c9_pminten |= value; + return 0; +} + +static int pmintenclr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + value &= (1 << 31); + env->cp15.c9_pminten &= ~value; + return 0; +} + static const ARMCPRegInfo v7_cp_reginfo[] = { /* DBGDRAR, DBGDSAR: always RAZ since we don't implement memory mapped * debug components @@ -109,6 +200,62 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { /* the old v6 WFI, UNPREDICTABLE in v7 but we choose to NOP */ { .name = "NOP", .cp = 15, .crn = 7, .crm = 0, .opc1 = 0, .opc2 = 4, .access = PL1_W, .type = ARM_CP_NOP }, + /* Performance monitors are implementation defined in v7, + * but with an ARM recommended set of registers, which we + * follow (although we don't actually implement any counters) + * + * Performance registers fall into three categories: + * (a) always UNDEF in PL0, RW in PL1 (PMINTENSET, PMINTENCLR) + * (b) RO in PL0 (ie UNDEF on write), RW in PL1 (PMUSERENR) + * (c) UNDEF in PL0 if PMUSERENR.EN==0, otherwise accessible (all others) + * For the cases controlled by PMUSERENR we must set .access to PL0_RW + * or PL0_RO as appropriate and then check PMUSERENR in the helper fn. + */ + { .name = "PMCNTENSET", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 1, + .access = PL0_RW, .resetvalue = 0, + .fieldoffset = offsetof(CPUARMState, cp15.c9_pmcnten), + .readfn = pmreg_read, .writefn = pmcntenset_write }, + { .name = "PMCNTENCLR", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 2, + .access = PL0_RW, .fieldoffset = offsetof(CPUARMState, cp15.c9_pmcnten), + .readfn = pmreg_read, .writefn = pmcntenclr_write }, + { .name = "PMOVSR", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 3, + .access = PL0_RW, .fieldoffset = offsetof(CPUARMState, cp15.c9_pmovsr), + .readfn = pmreg_read, .writefn = pmovsr_write }, + /* Unimplemented so WI. Strictly speaking write accesses in PL0 should + * respect PMUSERENR. + */ + { .name = "PMSWINC", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 4, + .access = PL0_W, .type = ARM_CP_NOP }, + /* Since we don't implement any events, writing to PMSELR is UNPREDICTABLE. + * We choose to RAZ/WI. XXX should respect PMUSERENR. + */ + { .name = "PMSELR", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 5, + .access = PL0_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + /* Unimplemented, RAZ/WI. XXX PMUSERENR */ + { .name = "PMCCNTR", .cp = 15, .crn = 9, .crm = 13, .opc1 = 0, .opc2 = 0, + .access = PL0_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "PMXEVTYPER", .cp = 15, .crn = 9, .crm = 13, .opc1 = 0, .opc2 = 1, + .access = PL0_RW, + .fieldoffset = offsetof(CPUARMState, cp15.c9_pmxevtyper), + .readfn = pmreg_read, .writefn = pmxevtyper_write }, + /* Unimplemented, RAZ/WI. XXX PMUSERENR */ + { .name = "PMXEVCNTR", .cp = 15, .crn = 9, .crm = 13, .opc1 = 0, .opc2 = 2, + .access = PL0_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "PMUSERENR", .cp = 15, .crn = 9, .crm = 14, .opc1 = 0, .opc2 = 0, + .access = PL0_R | PL1_RW, + .fieldoffset = offsetof(CPUARMState, cp15.c9_pmuserenr), + .resetvalue = 0, + .writefn = pmuserenr_write }, + { .name = "PMINTENSET", .cp = 15, .crn = 9, .crm = 14, .opc1 = 0, .opc2 = 1, + .access = PL1_RW, + .fieldoffset = offsetof(CPUARMState, cp15.c9_pminten), + .resetvalue = 0, + .writefn = pmintenset_write }, + { .name = "PMINTENCLR", .cp = 15, .crn = 9, .crm = 14, .opc1 = 0, .opc2 = 2, + .access = PL1_RW, + .fieldoffset = offsetof(CPUARMState, cp15.c9_pminten), + .resetvalue = 0, + .writefn = pmintenclr_write }, REGINFO_SENTINEL }; @@ -189,6 +336,16 @@ void register_cp_regs_for_features(ARMCPU *cpu) define_arm_cp_regs(cpu, v6k_cp_reginfo); } if (arm_feature(env, ARM_FEATURE_V7)) { + /* v7 performance monitor control register: same implementor + * field as main ID register, and we implement no event counters. + */ + ARMCPRegInfo pmcr = { + .name = "PMCR", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 0, + .access = PL0_RW, .resetvalue = cpu->midr & 0xff000000, + .fieldoffset = offsetof(CPUARMState, cp15.c9_pmcr), + .readfn = pmreg_read, .writefn = pmcr_write + }; + define_one_arm_cp_reg(cpu, &pmcr); define_arm_cp_regs(cpu, v7_cp_reginfo); } else { define_arm_cp_regs(cpu, not_v7_cp_reginfo); @@ -1533,81 +1690,6 @@ void HELPER(set_cp15)(CPUARMState *env, uint32_t insn, uint32_t val) case 1: /* TCM memory region registers. */ /* Not implemented. */ goto bad_reg; - case 12: /* Performance monitor control */ - /* Performance monitors are implementation defined in v7, - * but with an ARM recommended set of registers, which we - * follow (although we don't actually implement any counters) - */ - if (!arm_feature(env, ARM_FEATURE_V7)) { - goto bad_reg; - } - switch (op2) { - case 0: /* performance monitor control register */ - /* only the DP, X, D and E bits are writable */ - env->cp15.c9_pmcr &= ~0x39; - env->cp15.c9_pmcr |= (val & 0x39); - break; - case 1: /* Count enable set register */ - val &= (1 << 31); - env->cp15.c9_pmcnten |= val; - break; - case 2: /* Count enable clear */ - val &= (1 << 31); - env->cp15.c9_pmcnten &= ~val; - break; - case 3: /* Overflow flag status */ - env->cp15.c9_pmovsr &= ~val; - break; - case 4: /* Software increment */ - /* RAZ/WI since we don't implement the software-count event */ - break; - case 5: /* Event counter selection register */ - /* Since we don't implement any events, writing to this register - * is actually UNPREDICTABLE. So we choose to RAZ/WI. - */ - break; - default: - goto bad_reg; - } - break; - case 13: /* Performance counters */ - if (!arm_feature(env, ARM_FEATURE_V7)) { - goto bad_reg; - } - switch (op2) { - case 0: /* Cycle count register: not implemented, so RAZ/WI */ - break; - case 1: /* Event type select */ - env->cp15.c9_pmxevtyper = val & 0xff; - break; - case 2: /* Event count register */ - /* Unimplemented (we have no events), RAZ/WI */ - break; - default: - goto bad_reg; - } - break; - case 14: /* Performance monitor control */ - if (!arm_feature(env, ARM_FEATURE_V7)) { - goto bad_reg; - } - switch (op2) { - case 0: /* user enable */ - env->cp15.c9_pmuserenr = val & 1; - /* changes access rights for cp registers, so flush tbs */ - tb_flush(env); - break; - case 1: /* interrupt enable set */ - /* We have no event counters so only the C bit can be changed */ - val &= (1 << 31); - env->cp15.c9_pminten |= val; - break; - case 2: /* interrupt enable clear */ - val &= (1 << 31); - env->cp15.c9_pminten &= ~val; - break; - } - break; default: goto bad_reg; } @@ -1964,51 +2046,6 @@ uint32_t HELPER(get_cp15)(CPUARMState *env, uint32_t insn) goto bad_reg; } break; - case 12: /* Performance monitor control */ - if (!arm_feature(env, ARM_FEATURE_V7)) { - goto bad_reg; - } - switch (op2) { - case 0: /* performance monitor control register */ - return env->cp15.c9_pmcr; - case 1: /* count enable set */ - case 2: /* count enable clear */ - return env->cp15.c9_pmcnten; - case 3: /* overflow flag status */ - return env->cp15.c9_pmovsr; - case 4: /* software increment */ - case 5: /* event counter selection register */ - return 0; /* Unimplemented, RAZ/WI */ - default: - goto bad_reg; - } - case 13: /* Performance counters */ - if (!arm_feature(env, ARM_FEATURE_V7)) { - goto bad_reg; - } - switch (op2) { - case 1: /* Event type select */ - return env->cp15.c9_pmxevtyper; - case 0: /* Cycle count register */ - case 2: /* Event count register */ - /* Unimplemented, so RAZ/WI */ - return 0; - default: - goto bad_reg; - } - case 14: /* Performance monitor control */ - if (!arm_feature(env, ARM_FEATURE_V7)) { - goto bad_reg; - } - switch (op2) { - case 0: /* user enable */ - return env->cp15.c9_pmuserenr; - case 1: /* interrupt enable set */ - case 2: /* interrupt enable clear */ - return env->cp15.c9_pminten; - default: - goto bad_reg; - } default: goto bad_reg; } diff --git a/target-arm/translate.c b/target-arm/translate.c index e6b0d8707c..f4e9435c4b 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -2439,30 +2439,6 @@ static int disas_dsp_insn(CPUARMState *env, DisasContext *s, uint32_t insn) return 1; } -static int cp15_user_ok(CPUARMState *env, uint32_t insn) -{ - int cpn = (insn >> 16) & 0xf; - int cpm = insn & 0xf; - int op = ((insn >> 5) & 7) | ((insn >> 18) & 0x38); - - if (arm_feature(env, ARM_FEATURE_V7) && cpn == 9) { - /* Performance monitor registers fall into three categories: - * (a) always UNDEF in usermode - * (b) UNDEF only if PMUSERENR.EN is 0 - * (c) always read OK and UNDEF on write (PMUSERENR only) - */ - if ((cpm == 12 && (op < 6)) || - (cpm == 13 && (op < 3))) { - return env->cp15.c9_pmuserenr; - } else if (cpm == 14 && op == 0 && (insn & ARM_CP_RW_BIT)) { - /* PMUSERENR, read only */ - return 1; - } - return 0; - } - return 0; -} - /* Disassemble system coprocessor (cp15) instruction. Return nonzero if instruction is not defined. */ static int disas_cp15_insn(CPUARMState *env, DisasContext *s, uint32_t insn) @@ -2487,7 +2463,7 @@ static int disas_cp15_insn(CPUARMState *env, DisasContext *s, uint32_t insn) return 1; } - if (IS_USER(s) && !cp15_user_ok(env, insn)) { + if (IS_USER(s)) { return 1; } -- cgit v1.2.3 From 6cc7a3aee6259ca9d94312b1af0255c92a30fe34 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jun 2012 11:57:12 +0000 Subject: target-arm: Convert generic timer cp15 regs Convert the (dummy) generic timer cp15 implementation. Signed-off-by: Peter Maydell --- target-arm/helper.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index ebe6a55910..2d58eb5b6a 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -317,6 +317,14 @@ static const ARMCPRegInfo v6k_cp_reginfo[] = { REGINFO_SENTINEL }; +static const ARMCPRegInfo generic_timer_cp_reginfo[] = { + /* Dummy implementation: RAZ/WI the whole crn=14 space */ + { .name = "GENERIC_TIMER", .cp = 15, .crn = 14, + .crm = CP_ANY, .opc1 = CP_ANY, .opc2 = CP_ANY, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + REGINFO_SENTINEL +}; + void register_cp_regs_for_features(ARMCPU *cpu) { /* Register all the coprocessor registers based on feature bits */ @@ -353,6 +361,9 @@ void register_cp_regs_for_features(ARMCPU *cpu) if (arm_feature(env, ARM_FEATURE_THUMB2EE)) { define_arm_cp_regs(cpu, t2ee_cp_reginfo); } + if (arm_feature(env, ARM_FEATURE_GENERIC_TIMER)) { + define_arm_cp_regs(cpu, generic_timer_cp_reginfo); + } } ARMCPU *cpu_arm_init(const char *cpu_model) @@ -1720,12 +1731,6 @@ void HELPER(set_cp15)(CPUARMState *env, uint32_t insn, uint32_t val) goto bad_reg; } break; - case 14: /* Generic timer */ - if (arm_feature(env, ARM_FEATURE_GENERIC_TIMER)) { - /* Dummy implementation: RAZ/WI for all */ - break; - } - goto bad_reg; case 15: /* Implementation specific. */ if (arm_feature(env, ARM_FEATURE_XSCALE)) { if (op2 == 0 && crm == 1) { @@ -2065,12 +2070,6 @@ uint32_t HELPER(get_cp15)(CPUARMState *env, uint32_t insn) default: goto bad_reg; } - case 14: /* Generic timer */ - if (arm_feature(env, ARM_FEATURE_GENERIC_TIMER)) { - /* Dummy implementation: RAZ/WI for all */ - return 0; - } - goto bad_reg; case 15: /* Implementation specific. */ if (arm_feature(env, ARM_FEATURE_XSCALE)) { if (op2 == 0 && crm == 1) -- cgit v1.2.3 From c983fe6cf199f919e1d9b24c86167e46ac20d8b8 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jun 2012 11:57:13 +0000 Subject: target-arm: Convert cp15 c3 register Convert the cp15 c3 register (MMU domain access control or MPU write buffer control). NB that this is horribly underdecoded for modern cores (should be crn=3,crm=0, opc1=0,opc2=0) but this change preserves the existing QEMU behaviour. Signed-off-by: Peter Maydell --- target-arm/helper.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 2d58eb5b6a..d579a2082c 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -56,6 +56,13 @@ static int vfp_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg) return 0; } +static int dacr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) +{ + env->cp15.c3 = value; + tlb_flush(env, 1); /* Flush TLB as domain not tracked in TLB */ + return 0; +} + static const ARMCPRegInfo cp_reginfo[] = { /* DBGDIDR: just RAZ. In particular this means the "debug architecture * version" bits will read as a reserved value, which should cause @@ -63,6 +70,11 @@ static const ARMCPRegInfo cp_reginfo[] = { */ { .name = "DBGDIDR", .cp = 14, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 0, .access = PL0_R, .type = ARM_CP_CONST, .resetvalue = 0 }, + /* MMU Domain access control / MPU write buffer control */ + { .name = "DACR", .cp = 15, + .crn = 3, .crm = CP_ANY, .opc1 = CP_ANY, .opc2 = CP_ANY, + .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c3), + .resetvalue = 0, .writefn = dacr_write }, REGINFO_SENTINEL }; @@ -1551,10 +1563,6 @@ void HELPER(set_cp15)(CPUARMState *env, uint32_t insn, uint32_t val) } } break; - case 3: /* MMU Domain access control / MPU write buffer control. */ - env->cp15.c3 = val; - tlb_flush(env, 1); /* Flush TLB as domain not tracked in TLB */ - break; case 4: /* Reserved. */ goto bad_reg; case 5: /* MMU Fault status / MPU access permission. */ @@ -1942,8 +1950,6 @@ uint32_t HELPER(get_cp15)(CPUARMState *env, uint32_t insn) goto bad_reg; } } - case 3: /* MMU Domain access control / MPU write buffer control. */ - return env->cp15.c3; case 4: /* Reserved. */ goto bad_reg; case 5: /* MMU Fault status / MPU access permission. */ -- cgit v1.2.3 From 18032bec5cd4fa3e45987e021b2f89fbff12ba5f Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jun 2012 11:57:13 +0000 Subject: target-arm: Convert MMU fault status cp15 registers Convert the MMU fault status and MPU access permission cp15 registers to the new scheme. Signed-off-by: Peter Maydell --- target-arm/helper.c | 188 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 107 insertions(+), 81 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index d579a2082c..d2c7b9ff22 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -337,6 +337,99 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { REGINFO_SENTINEL }; +/* Return basic MPU access permission bits. */ +static uint32_t simple_mpu_ap_bits(uint32_t val) +{ + uint32_t ret; + uint32_t mask; + int i; + ret = 0; + mask = 3; + for (i = 0; i < 16; i += 2) { + ret |= (val >> i) & mask; + mask <<= 2; + } + return ret; +} + +/* Pad basic MPU access permission bits to extended format. */ +static uint32_t extended_mpu_ap_bits(uint32_t val) +{ + uint32_t ret; + uint32_t mask; + int i; + ret = 0; + mask = 3; + for (i = 0; i < 16; i += 2) { + ret |= (val & mask) << i; + mask <<= 2; + } + return ret; +} + +static int pmsav5_data_ap_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + env->cp15.c5_data = extended_mpu_ap_bits(value); + return 0; +} + +static int pmsav5_data_ap_read(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t *value) +{ + *value = simple_mpu_ap_bits(env->cp15.c5_data); + return 0; +} + +static int pmsav5_insn_ap_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + env->cp15.c5_insn = extended_mpu_ap_bits(value); + return 0; +} + +static int pmsav5_insn_ap_read(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t *value) +{ + *value = simple_mpu_ap_bits(env->cp15.c5_insn); + return 0; +} + +static const ARMCPRegInfo pmsav5_cp_reginfo[] = { + { .name = "DATA_AP", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, + .fieldoffset = offsetof(CPUARMState, cp15.c5_data), .resetvalue = 0, + .readfn = pmsav5_data_ap_read, .writefn = pmsav5_data_ap_write, }, + { .name = "INSN_AP", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 1, + .access = PL1_RW, + .fieldoffset = offsetof(CPUARMState, cp15.c5_insn), .resetvalue = 0, + .readfn = pmsav5_insn_ap_read, .writefn = pmsav5_insn_ap_write, }, + { .name = "DATA_EXT_AP", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 2, + .access = PL1_RW, + .fieldoffset = offsetof(CPUARMState, cp15.c5_data), .resetvalue = 0, }, + { .name = "INSN_EXT_AP", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 3, + .access = PL1_RW, + .fieldoffset = offsetof(CPUARMState, cp15.c5_insn), .resetvalue = 0, }, + REGINFO_SENTINEL +}; + +static const ARMCPRegInfo vmsa_cp_reginfo[] = { + { .name = "DFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, + .fieldoffset = offsetof(CPUARMState, cp15.c5_data), .resetvalue = 0, }, + { .name = "IFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 1, + .access = PL1_RW, + .fieldoffset = offsetof(CPUARMState, cp15.c5_insn), .resetvalue = 0, }, + REGINFO_SENTINEL +}; + +static const ARMCPRegInfo omap_cp_reginfo[] = { + { .name = "DFSR", .cp = 15, .crn = 5, .crm = CP_ANY, + .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_RW, .type = ARM_CP_OVERRIDE, + .fieldoffset = offsetof(CPUARMState, cp15.c5_data), .resetvalue = 0, }, + REGINFO_SENTINEL +}; + void register_cp_regs_for_features(ARMCPU *cpu) { /* Register all the coprocessor registers based on feature bits */ @@ -370,12 +463,26 @@ void register_cp_regs_for_features(ARMCPU *cpu) } else { define_arm_cp_regs(cpu, not_v7_cp_reginfo); } + if (arm_feature(env, ARM_FEATURE_MPU)) { + /* These are the MPU registers prior to PMSAv6. Any new + * PMSA core later than the ARM946 will require that we + * implement the PMSAv6 or PMSAv7 registers, which are + * completely different. + */ + assert(!arm_feature(env, ARM_FEATURE_V6)); + define_arm_cp_regs(cpu, pmsav5_cp_reginfo); + } else { + define_arm_cp_regs(cpu, vmsa_cp_reginfo); + } if (arm_feature(env, ARM_FEATURE_THUMB2EE)) { define_arm_cp_regs(cpu, t2ee_cp_reginfo); } if (arm_feature(env, ARM_FEATURE_GENERIC_TIMER)) { define_arm_cp_regs(cpu, generic_timer_cp_reginfo); } + if (arm_feature(env, ARM_FEATURE_OMAPCP)) { + define_arm_cp_regs(cpu, omap_cp_reginfo); + } } ARMCPU *cpu_arm_init(const char *cpu_model) @@ -1444,36 +1551,6 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUARMState *env, target_ulong addr) return phys_addr; } -/* Return basic MPU access permission bits. */ -static uint32_t simple_mpu_ap_bits(uint32_t val) -{ - uint32_t ret; - uint32_t mask; - int i; - ret = 0; - mask = 3; - for (i = 0; i < 16; i += 2) { - ret |= (val >> i) & mask; - mask <<= 2; - } - return ret; -} - -/* Pad basic MPU access permission bits to extended format. */ -static uint32_t extended_mpu_ap_bits(uint32_t val) -{ - uint32_t ret; - uint32_t mask; - int i; - ret = 0; - mask = 3; - for (i = 0; i < 16; i += 2) { - ret |= (val & mask) << i; - mask <<= 2; - } - return ret; -} - void HELPER(set_cp15)(CPUARMState *env, uint32_t insn, uint32_t val) { int op1; @@ -1565,34 +1642,6 @@ void HELPER(set_cp15)(CPUARMState *env, uint32_t insn, uint32_t val) break; case 4: /* Reserved. */ goto bad_reg; - case 5: /* MMU Fault status / MPU access permission. */ - if (arm_feature(env, ARM_FEATURE_OMAPCP)) - op2 = 0; - switch (op2) { - case 0: - if (arm_feature(env, ARM_FEATURE_MPU)) - val = extended_mpu_ap_bits(val); - env->cp15.c5_data = val; - break; - case 1: - if (arm_feature(env, ARM_FEATURE_MPU)) - val = extended_mpu_ap_bits(val); - env->cp15.c5_insn = val; - break; - case 2: - if (!arm_feature(env, ARM_FEATURE_MPU)) - goto bad_reg; - env->cp15.c5_data = val; - break; - case 3: - if (!arm_feature(env, ARM_FEATURE_MPU)) - goto bad_reg; - env->cp15.c5_insn = val; - break; - default: - goto bad_reg; - } - break; case 6: /* MMU Fault address / MPU base/size. */ if (arm_feature(env, ARM_FEATURE_MPU)) { if (crm >= 8) @@ -1952,29 +2001,6 @@ uint32_t HELPER(get_cp15)(CPUARMState *env, uint32_t insn) } case 4: /* Reserved. */ goto bad_reg; - case 5: /* MMU Fault status / MPU access permission. */ - if (arm_feature(env, ARM_FEATURE_OMAPCP)) - op2 = 0; - switch (op2) { - case 0: - if (arm_feature(env, ARM_FEATURE_MPU)) - return simple_mpu_ap_bits(env->cp15.c5_data); - return env->cp15.c5_data; - case 1: - if (arm_feature(env, ARM_FEATURE_MPU)) - return simple_mpu_ap_bits(env->cp15.c5_insn); - return env->cp15.c5_insn; - case 2: - if (!arm_feature(env, ARM_FEATURE_MPU)) - goto bad_reg; - return env->cp15.c5_data; - case 3: - if (!arm_feature(env, ARM_FEATURE_MPU)) - goto bad_reg; - return env->cp15.c5_insn; - default: - goto bad_reg; - } case 6: /* MMU Fault address. */ if (arm_feature(env, ARM_FEATURE_MPU)) { if (crm >= 8) -- cgit v1.2.3 From ecce5c3c90653b82c2910da53210ba4ce589da89 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jun 2012 11:57:14 +0000 Subject: target-arm: Convert cp15 crn=2 registers Convert the cp15 crn=2 registers (MMU page table control, MPU cache control) to the new scheme. Signed-off-by: Peter Maydell --- target-arm/cpu.c | 1 - target-arm/helper.c | 88 ++++++++++++++++++++--------------------------------- 2 files changed, 33 insertions(+), 56 deletions(-) diff --git a/target-arm/cpu.c b/target-arm/cpu.c index 00987870cd..8fcb7302a5 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -131,7 +131,6 @@ static void arm_cpu_reset(CPUState *s) } } env->vfp.xregs[ARM_VFP_FPEXC] = 0; - env->cp15.c2_base_mask = 0xffffc000u; #endif set_flush_to_zero(1, &env->vfp.standard_fp_status); set_flush_inputs_to_zero(1, &env->vfp.standard_fp_status); diff --git a/target-arm/helper.c b/target-arm/helper.c index d2c7b9ff22..bda7947b43 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -410,9 +410,32 @@ static const ARMCPRegInfo pmsav5_cp_reginfo[] = { { .name = "INSN_EXT_AP", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 3, .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c5_insn), .resetvalue = 0, }, + { .name = "DCACHE_CFG", .cp = 15, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, + .fieldoffset = offsetof(CPUARMState, cp15.c2_data), .resetvalue = 0, }, + { .name = "ICACHE_CFG", .cp = 15, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 1, + .access = PL1_RW, + .fieldoffset = offsetof(CPUARMState, cp15.c2_insn), .resetvalue = 0, }, REGINFO_SENTINEL }; +static int vmsa_ttbcr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + value &= 7; + env->cp15.c2_control = value; + env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> value); + env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> value); + return 0; +} + +static void vmsa_ttbcr_reset(CPUARMState *env, const ARMCPRegInfo *ri) +{ + env->cp15.c2_base_mask = 0xffffc000u; + env->cp15.c2_control = 0; + env->cp15.c2_mask = 0; +} + static const ARMCPRegInfo vmsa_cp_reginfo[] = { { .name = "DFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 0, .access = PL1_RW, @@ -420,6 +443,16 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = { { .name = "IFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 1, .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c5_insn), .resetvalue = 0, }, + { .name = "TTBR0", .cp = 15, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, + .fieldoffset = offsetof(CPUARMState, cp15.c2_base0), .resetvalue = 0, }, + { .name = "TTBR1", .cp = 15, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 1, + .access = PL1_RW, + .fieldoffset = offsetof(CPUARMState, cp15.c2_base0), .resetvalue = 0, }, + { .name = "TTBCR", .cp = 15, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 2, + .access = PL1_RW, .writefn = vmsa_ttbcr_write, + .resetfn = vmsa_ttbcr_reset, + .fieldoffset = offsetof(CPUARMState, cp15.c2_control) }, REGINFO_SENTINEL }; @@ -1609,37 +1642,6 @@ void HELPER(set_cp15)(CPUARMState *env, uint32_t insn, uint32_t val) goto bad_reg; } break; - case 2: /* MMU Page table control / MPU cache control. */ - if (arm_feature(env, ARM_FEATURE_MPU)) { - switch (op2) { - case 0: - env->cp15.c2_data = val; - break; - case 1: - env->cp15.c2_insn = val; - break; - default: - goto bad_reg; - } - } else { - switch (op2) { - case 0: - env->cp15.c2_base0 = val; - break; - case 1: - env->cp15.c2_base1 = val; - break; - case 2: - val &= 7; - env->cp15.c2_control = val; - env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> val); - env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> val); - break; - default: - goto bad_reg; - } - } - break; case 4: /* Reserved. */ goto bad_reg; case 6: /* MMU Fault address / MPU base/size. */ @@ -1975,30 +1977,6 @@ uint32_t HELPER(get_cp15)(CPUARMState *env, uint32_t insn) default: goto bad_reg; } - case 2: /* MMU Page table control / MPU cache control. */ - if (arm_feature(env, ARM_FEATURE_MPU)) { - switch (op2) { - case 0: - return env->cp15.c2_data; - break; - case 1: - return env->cp15.c2_insn; - break; - default: - goto bad_reg; - } - } else { - switch (op2) { - case 0: - return env->cp15.c2_base0; - case 1: - return env->cp15.c2_base1; - case 2: - return env->cp15.c2_control; - default: - goto bad_reg; - } - } case 4: /* Reserved. */ goto bad_reg; case 6: /* MMU Fault address. */ -- cgit v1.2.3 From 08de207bc52108df5d8e9074909e98f5df8e1212 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jun 2012 11:57:14 +0000 Subject: target-arm: Convert cp15 crn=13 registers Convert the cp15 crn=13 registers (FCSEIDR, CONTEXTIDR, and the ARM946 Trace Process Identifier Register). Signed-off-by: Peter Maydell --- target-arm/helper.c | 61 +++++++++++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index bda7947b43..3cffa00a66 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -63,6 +63,31 @@ static int dacr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) return 0; } +static int fcse_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) +{ + if (env->cp15.c13_fcse != value) { + /* Unlike real hardware the qemu TLB uses virtual addresses, + * not modified virtual addresses, so this causes a TLB flush. + */ + tlb_flush(env, 1); + env->cp15.c13_fcse = value; + } + return 0; +} +static int contextidr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + if (env->cp15.c13_context != value && !arm_feature(env, ARM_FEATURE_MPU)) { + /* For VMSA (when not using the LPAE long descriptor page table + * format) this register includes the ASID, so do a TLB flush. + * For PMSA it is purely a process ID and no action is needed. + */ + tlb_flush(env, 1); + } + env->cp15.c13_context = value; + return 0; +} + static const ARMCPRegInfo cp_reginfo[] = { /* DBGDIDR: just RAZ. In particular this means the "debug architecture * version" bits will read as a reserved value, which should cause @@ -75,6 +100,12 @@ static const ARMCPRegInfo cp_reginfo[] = { .crn = 3, .crm = CP_ANY, .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c3), .resetvalue = 0, .writefn = dacr_write }, + { .name = "FCSEIDR", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c13_fcse), + .resetvalue = 0, .writefn = fcse_write }, + { .name = "CONTEXTIDR", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0, .opc2 = 1, + .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c13_fcse), + .resetvalue = 0, .writefn = contextidr_write }, REGINFO_SENTINEL }; @@ -1769,27 +1800,6 @@ void HELPER(set_cp15)(CPUARMState *env, uint32_t insn, uint32_t val) break; case 12: /* Reserved. */ goto bad_reg; - case 13: /* Process ID. */ - switch (op2) { - case 0: - /* Unlike real hardware the qemu TLB uses virtual addresses, - not modified virtual addresses, so this causes a TLB flush. - */ - if (env->cp15.c13_fcse != val) - tlb_flush(env, 1); - env->cp15.c13_fcse = val; - break; - case 1: - /* This changes the ASID, so do a TLB flush. */ - if (env->cp15.c13_context != val - && !arm_feature(env, ARM_FEATURE_MPU)) - tlb_flush(env, 0); - env->cp15.c13_context = val; - break; - default: - goto bad_reg; - } - break; case 15: /* Implementation specific. */ if (arm_feature(env, ARM_FEATURE_XSCALE)) { if (op2 == 0 && crm == 1) { @@ -2071,15 +2081,6 @@ uint32_t HELPER(get_cp15)(CPUARMState *env, uint32_t insn) case 11: /* TCM DMA control. */ case 12: /* Reserved. */ goto bad_reg; - case 13: /* Process ID. */ - switch (op2) { - case 0: - return env->cp15.c13_fcse; - case 1: - return env->cp15.c13_context; - default: - goto bad_reg; - } case 15: /* Implementation specific. */ if (arm_feature(env, ARM_FEATURE_XSCALE)) { if (op2 == 0 && crm == 1) -- cgit v1.2.3 From 4fdd17dd3505ea5444d08d1347783d2347ec3520 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jun 2012 11:57:15 +0000 Subject: target-arm: Convert cp15 crn=10 registers We RAZ/WI the entire block of crn=10 registers. Note that this actually covers not just the implementation-defined TLB lockdown registers but also a number of v7 VMSA memory attribute registers which we would need to implement to support TEX remap. We retain the previous QEMU behaviour in this conversion, though. Signed-off-by: Peter Maydell --- target-arm/helper.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 3cffa00a66..5fa4ed53c0 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -106,6 +106,11 @@ static const ARMCPRegInfo cp_reginfo[] = { { .name = "CONTEXTIDR", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0, .opc2 = 1, .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c13_fcse), .resetvalue = 0, .writefn = contextidr_write }, + /* ??? This covers not just the impdef TLB lockdown registers but also + * some v7VMSA registers relating to TEX remap, so it is overly broad. + */ + { .name = "TLB_LOCKDOWN", .cp = 15, .crn = 10, .crm = CP_ANY, + .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_RW, .type = ARM_CP_NOP }, REGINFO_SENTINEL }; @@ -1795,9 +1800,6 @@ void HELPER(set_cp15)(CPUARMState *env, uint32_t insn, uint32_t val) goto bad_reg; } break; - case 10: /* MMU TLB lockdown. */ - /* ??? TLB lockdown not implemented. */ - break; case 12: /* Reserved. */ goto bad_reg; case 15: /* Implementation specific. */ @@ -2075,9 +2077,6 @@ uint32_t HELPER(get_cp15)(CPUARMState *env, uint32_t insn) goto bad_reg; } break; - case 10: /* MMU TLB lockdown. */ - /* ??? TLB lockdown not implemented. */ - return 0; case 11: /* TCM DMA control. */ case 12: /* Reserved. */ goto bad_reg; -- cgit v1.2.3 From 1047b9d7bbda3d035e6d94c4a0e6d56d91ce95ec Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jun 2012 11:57:15 +0000 Subject: target-arm: Convert cp15 crn=15 registers Convert the cp15 crn=15 (implementation specific) registers to the new scheme. Signed-off-by: Peter Maydell --- target-arm/cpu.c | 40 ++++++++++- target-arm/cpu.h | 1 + target-arm/helper.c | 202 ++++++++++++++++++++++------------------------------ 3 files changed, 126 insertions(+), 117 deletions(-) diff --git a/target-arm/cpu.c b/target-arm/cpu.c index 8fcb7302a5..6190091f20 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -71,7 +71,6 @@ static void arm_cpu_reset(CPUState *s) memset(env, 0, offsetof(CPUARMState, breakpoints)); g_hash_table_foreach(cpu->cp_regs, cp_reg_reset, cpu); - env->cp15.c15_config_base_address = cpu->reset_cbar; env->cp15.c0_cpuid = cpu->midr; env->vfp.xregs[ARM_VFP_FPSID] = cpu->reset_fpsid; env->vfp.xregs[ARM_VFP_MVFR0] = cpu->mvfr0; @@ -92,7 +91,6 @@ static void arm_cpu_reset(CPUState *s) env->cp15.c0_c2[3] = cpu->id_isar3; env->cp15.c0_c2[4] = cpu->id_isar4; env->cp15.c0_c2[5] = cpu->id_isar5; - env->cp15.c15_i_min = 0xff0; env->cp15.c0_clid = cpu->clidr; memcpy(env->cp15.c0_ccsid, cpu->ccsidr, ARRAY_SIZE(cpu->ccsidr)); @@ -399,6 +397,35 @@ static void cortex_a8_initfn(Object *obj) cpu->ccsidr[2] = 0xf0000000; /* No L2 icache. */ } +static const ARMCPRegInfo cortexa9_cp_reginfo[] = { + /* power_control should be set to maximum latency. Again, + * default to 0 and set by private hook + */ + { .name = "A9_PWRCTL", .cp = 15, .crn = 15, .crm = 0, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, .resetvalue = 0, + .fieldoffset = offsetof(CPUARMState, cp15.c15_power_control) }, + { .name = "A9_DIAG", .cp = 15, .crn = 15, .crm = 0, .opc1 = 0, .opc2 = 1, + .access = PL1_RW, .resetvalue = 0, + .fieldoffset = offsetof(CPUARMState, cp15.c15_diagnostic) }, + { .name = "A9_PWRDIAG", .cp = 15, .crn = 15, .crm = 0, .opc1 = 0, .opc2 = 2, + .access = PL1_RW, .resetvalue = 0, + .fieldoffset = offsetof(CPUARMState, cp15.c15_power_diagnostic) }, + { .name = "NEONBUSY", .cp = 15, .crn = 15, .crm = 1, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST }, + /* TLB lockdown control */ + { .name = "TLB_LOCKR", .cp = 15, .crn = 15, .crm = 4, .opc1 = 5, .opc2 = 2, + .access = PL1_W, .resetvalue = 0, .type = ARM_CP_NOP }, + { .name = "TLB_LOCKW", .cp = 15, .crn = 15, .crm = 4, .opc1 = 5, .opc2 = 4, + .access = PL1_W, .resetvalue = 0, .type = ARM_CP_NOP }, + { .name = "TLB_VA", .cp = 15, .crn = 15, .crm = 5, .opc1 = 5, .opc2 = 2, + .access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST }, + { .name = "TLB_PA", .cp = 15, .crn = 15, .crm = 6, .opc1 = 5, .opc2 = 2, + .access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST }, + { .name = "TLB_ATTR", .cp = 15, .crn = 15, .crm = 7, .opc1 = 5, .opc2 = 2, + .access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST }, + REGINFO_SENTINEL +}; + static void cortex_a9_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); @@ -434,6 +461,15 @@ static void cortex_a9_initfn(Object *obj) cpu->clidr = (1 << 27) | (1 << 24) | 3; cpu->ccsidr[0] = 0xe00fe015; /* 16k L1 dcache. */ cpu->ccsidr[1] = 0x200fe015; /* 16k L1 icache. */ + { + ARMCPRegInfo cbar = { + .name = "CBAR", .cp = 15, .crn = 15, .crm = 0, .opc1 = 4, + .opc2 = 0, .access = PL1_R|PL3_W, .resetvalue = cpu->reset_cbar, + .fieldoffset = offsetof(CPUARMState, cp15.c15_config_base_address) + }; + define_one_arm_cp_reg(cpu, &cbar); + define_arm_cp_regs(cpu, cortexa9_cp_reginfo); + } } static void cortex_a15_initfn(Object *obj) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index a61cb07d4c..b94503d774 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -386,6 +386,7 @@ enum arm_features { ARM_FEATURE_VFP4, /* VFPv4 (implies that NEON is v2) */ ARM_FEATURE_GENERIC_TIMER, ARM_FEATURE_MVFR, /* Media and VFP Feature Registers 0 and 1 */ + ARM_FEATURE_DUMMY_C15_REGS, /* RAZ/WI all of cp15 crn=15 */ }; static inline int arm_feature(CPUARMState *env, int feature) diff --git a/target-arm/helper.c b/target-arm/helper.c index 5fa4ed53c0..0d7200f958 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -492,10 +492,91 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = { REGINFO_SENTINEL }; +static int omap_ticonfig_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + env->cp15.c15_ticonfig = value & 0xe7; + /* The OS_TYPE bit in this register changes the reported CPUID! */ + env->cp15.c0_cpuid = (value & (1 << 5)) ? + ARM_CPUID_TI915T : ARM_CPUID_TI925T; + return 0; +} + +static int omap_threadid_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + env->cp15.c15_threadid = value & 0xffff; + return 0; +} + +static int omap_wfi_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + /* Wait-for-interrupt (deprecated) */ + cpu_interrupt(env, CPU_INTERRUPT_HALT); + return 0; +} + static const ARMCPRegInfo omap_cp_reginfo[] = { { .name = "DFSR", .cp = 15, .crn = 5, .crm = CP_ANY, .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_RW, .type = ARM_CP_OVERRIDE, .fieldoffset = offsetof(CPUARMState, cp15.c5_data), .resetvalue = 0, }, + { .name = "", .cp = 15, .crn = 15, .crm = 0, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_NOP }, + { .name = "TICONFIG", .cp = 15, .crn = 15, .crm = 1, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, + .fieldoffset = offsetof(CPUARMState, cp15.c15_ticonfig), .resetvalue = 0, + .writefn = omap_ticonfig_write }, + { .name = "IMAX", .cp = 15, .crn = 15, .crm = 2, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, + .fieldoffset = offsetof(CPUARMState, cp15.c15_i_max), .resetvalue = 0, }, + { .name = "IMIN", .cp = 15, .crn = 15, .crm = 3, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, .resetvalue = 0xff0, + .fieldoffset = offsetof(CPUARMState, cp15.c15_i_min) }, + { .name = "THREADID", .cp = 15, .crn = 15, .crm = 4, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, + .fieldoffset = offsetof(CPUARMState, cp15.c15_threadid), .resetvalue = 0, + .writefn = omap_threadid_write }, + { .name = "TI925T_STATUS", .cp = 15, .crn = 15, + .crm = 8, .opc1 = 0, .opc2 = 0, .access = PL1_RW, + .readfn = arm_cp_read_zero, .writefn = omap_wfi_write, }, + /* TODO: Peripheral port remap register: + * On OMAP2 mcr p15, 0, rn, c15, c2, 4 sets up the interrupt controller + * base address at $rn & ~0xfff and map size of 0x200 << ($rn & 0xfff), + * when MMU is off. + */ + REGINFO_SENTINEL +}; + +static int xscale_cpar_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + value &= 0x3fff; + if (env->cp15.c15_cpar != value) { + /* Changes cp0 to cp13 behavior, so needs a TB flush. */ + tb_flush(env); + env->cp15.c15_cpar = value; + } + return 0; +} + +static const ARMCPRegInfo xscale_cp_reginfo[] = { + { .name = "XSCALE_CPAR", + .cp = 15, .crn = 15, .crm = 1, .opc1 = 0, .opc2 = 0, .access = PL1_RW, + .fieldoffset = offsetof(CPUARMState, cp15.c15_cpar), .resetvalue = 0, + .writefn = xscale_cpar_write, }, + REGINFO_SENTINEL +}; + +static const ARMCPRegInfo dummy_c15_cp_reginfo[] = { + /* RAZ/WI the whole crn=15 space, when we don't have a more specific + * implementation of this implementation-defined space. + * Ideally this should eventually disappear in favour of actually + * implementing the correct behaviour for all cores. + */ + { .name = "C15_IMPDEF", .cp = 15, .crn = 15, + .crm = CP_ANY, .opc1 = CP_ANY, .opc2 = CP_ANY, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, REGINFO_SENTINEL }; @@ -552,6 +633,12 @@ void register_cp_regs_for_features(ARMCPU *cpu) if (arm_feature(env, ARM_FEATURE_OMAPCP)) { define_arm_cp_regs(cpu, omap_cp_reginfo); } + if (arm_feature(env, ARM_FEATURE_XSCALE)) { + define_arm_cp_regs(cpu, xscale_cp_reginfo); + } + if (arm_feature(env, ARM_FEATURE_DUMMY_C15_REGS)) { + define_arm_cp_regs(cpu, dummy_c15_cp_reginfo); + } } ARMCPU *cpu_arm_init(const char *cpu_model) @@ -1802,58 +1889,6 @@ void HELPER(set_cp15)(CPUARMState *env, uint32_t insn, uint32_t val) break; case 12: /* Reserved. */ goto bad_reg; - case 15: /* Implementation specific. */ - if (arm_feature(env, ARM_FEATURE_XSCALE)) { - if (op2 == 0 && crm == 1) { - if (env->cp15.c15_cpar != (val & 0x3fff)) { - /* Changes cp0 to cp13 behavior, so needs a TB flush. */ - tb_flush(env); - env->cp15.c15_cpar = val & 0x3fff; - } - break; - } - goto bad_reg; - } - if (arm_feature(env, ARM_FEATURE_OMAPCP)) { - switch (crm) { - case 0: - break; - case 1: /* Set TI925T configuration. */ - env->cp15.c15_ticonfig = val & 0xe7; - env->cp15.c0_cpuid = (val & (1 << 5)) ? /* OS_TYPE bit */ - ARM_CPUID_TI915T : ARM_CPUID_TI925T; - break; - case 2: /* Set I_max. */ - env->cp15.c15_i_max = val; - break; - case 3: /* Set I_min. */ - env->cp15.c15_i_min = val; - break; - case 4: /* Set thread-ID. */ - env->cp15.c15_threadid = val & 0xffff; - break; - case 8: /* Wait-for-interrupt (deprecated). */ - cpu_interrupt(env, CPU_INTERRUPT_HALT); - break; - default: - goto bad_reg; - } - } - if (ARM_CPUID(env) == ARM_CPUID_CORTEXA9) { - switch (crm) { - case 0: - if ((op1 == 0) && (op2 == 0)) { - env->cp15.c15_power_control = val; - } else if ((op1 == 0) && (op2 == 1)) { - env->cp15.c15_diagnostic = val; - } else if ((op1 == 0) && (op2 == 2)) { - env->cp15.c15_power_diagnostic = val; - } - default: - break; - } - } - break; } return; bad_reg: @@ -2080,69 +2115,6 @@ uint32_t HELPER(get_cp15)(CPUARMState *env, uint32_t insn) case 11: /* TCM DMA control. */ case 12: /* Reserved. */ goto bad_reg; - case 15: /* Implementation specific. */ - if (arm_feature(env, ARM_FEATURE_XSCALE)) { - if (op2 == 0 && crm == 1) - return env->cp15.c15_cpar; - - goto bad_reg; - } - if (arm_feature(env, ARM_FEATURE_OMAPCP)) { - switch (crm) { - case 0: - return 0; - case 1: /* Read TI925T configuration. */ - return env->cp15.c15_ticonfig; - case 2: /* Read I_max. */ - return env->cp15.c15_i_max; - case 3: /* Read I_min. */ - return env->cp15.c15_i_min; - case 4: /* Read thread-ID. */ - return env->cp15.c15_threadid; - case 8: /* TI925T_status */ - return 0; - } - /* TODO: Peripheral port remap register: - * On OMAP2 mcr p15, 0, rn, c15, c2, 4 sets up the interrupt - * controller base address at $rn & ~0xfff and map size of - * 0x200 << ($rn & 0xfff), when MMU is off. */ - goto bad_reg; - } - if (ARM_CPUID(env) == ARM_CPUID_CORTEXA9) { - switch (crm) { - case 0: - if ((op1 == 4) && (op2 == 0)) { - /* The config_base_address should hold the value of - * the peripheral base. ARM should get this from a CPU - * object property, but that support isn't available in - * December 2011. Default to 0 for now and board models - * that care can set it by a private hook */ - return env->cp15.c15_config_base_address; - } else if ((op1 == 0) && (op2 == 0)) { - /* power_control should be set to maximum latency. Again, - default to 0 and set by private hook */ - return env->cp15.c15_power_control; - } else if ((op1 == 0) && (op2 == 1)) { - return env->cp15.c15_diagnostic; - } else if ((op1 == 0) && (op2 == 2)) { - return env->cp15.c15_power_diagnostic; - } - break; - case 1: /* NEON Busy */ - return 0; - case 5: /* tlb lockdown */ - case 6: - case 7: - if ((op1 == 5) && (op2 == 2)) { - return 0; - } - break; - default: - break; - } - goto bad_reg; - } - return 0; } bad_reg: /* ??? For debugging only. Should raise illegal instruction exception. */ -- cgit v1.2.3 From d929823fa1e425054d45702aaea4b2c487d17eb1 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jun 2012 11:57:16 +0000 Subject: target-arm: Convert cp15 MMU TLB control Convert cp15 MMU TLB control (crn=8) to new scheme. Signed-off-by: Peter Maydell --- target-arm/helper.c | 63 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 20 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 0d7200f958..8def356dfc 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -88,6 +88,38 @@ static int contextidr_write(CPUARMState *env, const ARMCPRegInfo *ri, return 0; } +static int tlbiall_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + /* Invalidate all (TLBIALL) */ + tlb_flush(env, 1); + return 0; +} + +static int tlbimva_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + /* Invalidate single TLB entry by MVA and ASID (TLBIMVA) */ + tlb_flush_page(env, value & TARGET_PAGE_MASK); + return 0; +} + +static int tlbiasid_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + /* Invalidate by ASID (TLBIASID) */ + tlb_flush(env, value == 0); + return 0; +} + +static int tlbimvaa_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + /* Invalidate single entry by MVA, all ASIDs (TLBIMVAA) */ + tlb_flush_page(env, value & TARGET_PAGE_MASK); + return 0; +} + static const ARMCPRegInfo cp_reginfo[] = { /* DBGDIDR: just RAZ. In particular this means the "debug architecture * version" bits will read as a reserved value, which should cause @@ -111,6 +143,17 @@ static const ARMCPRegInfo cp_reginfo[] = { */ { .name = "TLB_LOCKDOWN", .cp = 15, .crn = 10, .crm = CP_ANY, .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_RW, .type = ARM_CP_NOP }, + /* MMU TLB control. Note that the wildcarding means we cover not just + * the unified TLB ops but also the dside/iside/inner-shareable variants. + */ + { .name = "TLBIALL", .cp = 15, .crn = 8, .crm = CP_ANY, + .opc1 = CP_ANY, .opc2 = 0, .access = PL1_W, .writefn = tlbiall_write, }, + { .name = "TLBIMVA", .cp = 15, .crn = 8, .crm = CP_ANY, + .opc1 = CP_ANY, .opc2 = 1, .access = PL1_W, .writefn = tlbimva_write, }, + { .name = "TLBIASID", .cp = 15, .crn = 8, .crm = CP_ANY, + .opc1 = CP_ANY, .opc2 = 2, .access = PL1_W, .writefn = tlbiasid_write, }, + { .name = "TLBIMVAA", .cp = 15, .crn = 8, .crm = CP_ANY, + .opc1 = CP_ANY, .opc2 = 3, .access = PL1_W, .writefn = tlbimvaa_write, }, REGINFO_SENTINEL }; @@ -1835,24 +1878,6 @@ void HELPER(set_cp15)(CPUARMState *env, uint32_t insn, uint32_t val) } } break; - case 8: /* MMU TLB control. */ - switch (op2) { - case 0: /* Invalidate all (TLBIALL) */ - tlb_flush(env, 1); - break; - case 1: /* Invalidate single TLB entry by MVA and ASID (TLBIMVA) */ - tlb_flush_page(env, val & TARGET_PAGE_MASK); - break; - case 2: /* Invalidate by ASID (TLBIASID) */ - tlb_flush(env, val == 0); - break; - case 3: /* Invalidate single entry by MVA, all ASIDs (TLBIMVAA) */ - tlb_flush_page(env, val & TARGET_PAGE_MASK); - break; - default: - goto bad_reg; - } - break; case 9: if (arm_feature(env, ARM_FEATURE_OMAPCP)) break; @@ -2065,8 +2090,6 @@ uint32_t HELPER(get_cp15)(CPUARMState *env, uint32_t insn) /* FIXME: Should only clear Z flag if destination is r15. */ env->ZF = 0; return 0; - case 8: /* MMU TLB control. */ - goto bad_reg; case 9: switch (crm) { case 0: /* Cache lockdown */ -- cgit v1.2.3 From 4a501606662a07e7089d3e6f7021490d24b16cb1 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jun 2012 11:57:16 +0000 Subject: target-arm: Convert cp15 VA-PA translation registers Convert the cp15 VA-PA translation registers (a subset of the crn=7 regs) to the new scheme. Signed-off-by: Peter Maydell --- target-arm/helper.c | 108 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 65 insertions(+), 43 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 8def356dfc..b7fc2dbf0f 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -4,6 +4,13 @@ #include "host-utils.h" #include "sysemu.h" +#ifndef CONFIG_USER_ONLY +static inline int get_phys_addr(CPUARMState *env, uint32_t address, + int access_type, int is_user, + uint32_t *phys_ptr, int *prot, + target_ulong *page_size); +#endif + static int vfp_gdb_get_reg(CPUARMState *env, uint8_t *buf, int reg) { int nregs; @@ -416,6 +423,61 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { REGINFO_SENTINEL }; +static int par_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) +{ + if (arm_feature(env, ARM_FEATURE_V7)) { + env->cp15.c7_par = value & 0xfffff6ff; + } else { + env->cp15.c7_par = value & 0xfffff1ff; + } + return 0; +} + +#ifndef CONFIG_USER_ONLY +/* get_phys_addr() isn't present for user-mode-only targets */ +static int ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) +{ + uint32_t phys_addr; + target_ulong page_size; + int prot; + int ret, is_user = ri->opc2 & 2; + int access_type = ri->opc2 & 1; + + if (ri->opc2 & 4) { + /* Other states are only available with TrustZone */ + return EXCP_UDEF; + } + ret = get_phys_addr(env, value, access_type, is_user, + &phys_addr, &prot, &page_size); + if (ret == 0) { + /* We do not set any attribute bits in the PAR */ + if (page_size == (1 << 24) + && arm_feature(env, ARM_FEATURE_V7)) { + env->cp15.c7_par = (phys_addr & 0xff000000) | 1 << 1; + } else { + env->cp15.c7_par = phys_addr & 0xfffff000; + } + } else { + env->cp15.c7_par = ((ret & (10 << 1)) >> 5) | + ((ret & (12 << 1)) >> 6) | + ((ret & 0xf) << 1) | 1; + } + return 0; +} +#endif + +static const ARMCPRegInfo vapa_cp_reginfo[] = { + { .name = "PAR", .cp = 15, .crn = 7, .crm = 4, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, .resetvalue = 0, + .fieldoffset = offsetof(CPUARMState, cp15.c7_par), + .writefn = par_write }, +#ifndef CONFIG_USER_ONLY + { .name = "ATS", .cp = 15, .crn = 7, .crm = 8, .opc1 = 0, .opc2 = CP_ANY, + .access = PL1_W, .writefn = ats_write }, +#endif + REGINFO_SENTINEL +}; + /* Return basic MPU access permission bits. */ static uint32_t simple_mpu_ap_bits(uint32_t val) { @@ -673,6 +735,9 @@ void register_cp_regs_for_features(ARMCPU *cpu) if (arm_feature(env, ARM_FEATURE_GENERIC_TIMER)) { define_arm_cp_regs(cpu, generic_timer_cp_reginfo); } + if (arm_feature(env, ARM_FEATURE_VAPA)) { + define_arm_cp_regs(cpu, vapa_cp_reginfo); + } if (arm_feature(env, ARM_FEATURE_OMAPCP)) { define_arm_cp_regs(cpu, omap_cp_reginfo); } @@ -1837,46 +1902,6 @@ void HELPER(set_cp15)(CPUARMState *env, uint32_t insn, uint32_t val) if (op1 != 0) { goto bad_reg; } - /* No cache, so nothing to do except VA->PA translations. */ - if (arm_feature(env, ARM_FEATURE_VAPA)) { - switch (crm) { - case 4: - if (arm_feature(env, ARM_FEATURE_V7)) { - env->cp15.c7_par = val & 0xfffff6ff; - } else { - env->cp15.c7_par = val & 0xfffff1ff; - } - break; - case 8: { - uint32_t phys_addr; - target_ulong page_size; - int prot; - int ret, is_user = op2 & 2; - int access_type = op2 & 1; - - if (op2 & 4) { - /* Other states are only available with TrustZone */ - goto bad_reg; - } - ret = get_phys_addr(env, val, access_type, is_user, - &phys_addr, &prot, &page_size); - if (ret == 0) { - /* We do not set any attribute bits in the PAR */ - if (page_size == (1 << 24) - && arm_feature(env, ARM_FEATURE_V7)) { - env->cp15.c7_par = (phys_addr & 0xff000000) | 1 << 1; - } else { - env->cp15.c7_par = phys_addr & 0xfffff000; - } - } else { - env->cp15.c7_par = ((ret & (10 << 1)) >> 5) | - ((ret & (12 << 1)) >> 6) | - ((ret & 0xf) << 1) | 1; - } - break; - } - } - } break; case 9: if (arm_feature(env, ARM_FEATURE_OMAPCP)) @@ -2084,9 +2109,6 @@ uint32_t HELPER(get_cp15)(CPUARMState *env, uint32_t insn) } } case 7: /* Cache control. */ - if (crm == 4 && op1 == 0 && op2 == 0) { - return env->cp15.c7_par; - } /* FIXME: Should only clear Z flag if destination is r15. */ env->ZF = 0; return 0; -- cgit v1.2.3 From c480421426c984068a27502c2948d2fa51b8cf96 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jun 2012 11:57:17 +0000 Subject: target-arm: convert cp15 crn=7 registers Convert the cp15 crn=7 registers to the new scheme. Note that to do this we have to distinguish some registers used on the ARM9 and ARM10 from some which are ARM1176 only. This is because the old code returned a value of 0 but always set the Z flag (by clearing env->ZF, since we store the Z flag in CPUState inverted). This is inconsistent with actual ARM CPU behaviour, which only sets flags for reads to r15 and sets them based on the top bits of the result. However it happened to work for the two common use cases for cp15 crn=7 reads: * On ARM9 and ARM10 the cache clean-and-test operations are typically done with a destination of r15 so that you can do a "loop: mrc ... ; bne loop" to keep cleaning until the cache is finally clean; always setting the Z flag means this loop terminates immediately * on ARM1176 the Cache Dirty Status Register reads as zero if the cache is dirty; returning 0 means this is correctly implemented for QEMU Since the new coprocessor register framework does the right thing of always setting flags based on the returned result for reads to r15, we need to split these up so that we can return (1<<30) for the ARM9/ARM10 registers but 0 for the ARM1176 one. This allows us to remove the nasty hack which always sets Z. Signed-off-by: Peter Maydell --- target-arm/cpu.c | 19 ++++++++++++++++ target-arm/cpu.h | 3 +++ target-arm/helper.c | 63 +++++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 74 insertions(+), 11 deletions(-) diff --git a/target-arm/cpu.c b/target-arm/cpu.c index 6190091f20..f8534a78b3 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -220,6 +220,8 @@ static void arm926_initfn(Object *obj) ARMCPU *cpu = ARM_CPU(obj); set_feature(&cpu->env, ARM_FEATURE_V5); set_feature(&cpu->env, ARM_FEATURE_VFP); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); + set_feature(&cpu->env, ARM_FEATURE_CACHE_TEST_CLEAN); cpu->midr = ARM_CPUID_ARM926; cpu->reset_fpsid = 0x41011090; cpu->ctr = 0x1dd20d2; @@ -231,6 +233,7 @@ static void arm946_initfn(Object *obj) ARMCPU *cpu = ARM_CPU(obj); set_feature(&cpu->env, ARM_FEATURE_V5); set_feature(&cpu->env, ARM_FEATURE_MPU); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); cpu->midr = ARM_CPUID_ARM946; cpu->ctr = 0x0f004006; cpu->reset_sctlr = 0x00000078; @@ -242,6 +245,8 @@ static void arm1026_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_V5); set_feature(&cpu->env, ARM_FEATURE_VFP); set_feature(&cpu->env, ARM_FEATURE_AUXCR); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); + set_feature(&cpu->env, ARM_FEATURE_CACHE_TEST_CLEAN); cpu->midr = ARM_CPUID_ARM1026; cpu->reset_fpsid = 0x410110a0; cpu->ctr = 0x1dd20d2; @@ -260,6 +265,9 @@ static void arm1136_r2_initfn(Object *obj) */ set_feature(&cpu->env, ARM_FEATURE_V6); set_feature(&cpu->env, ARM_FEATURE_VFP); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); + set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG); + set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS); cpu->midr = ARM_CPUID_ARM1136_R2; cpu->reset_fpsid = 0x410120b4; cpu->mvfr0 = 0x11111111; @@ -286,6 +294,9 @@ static void arm1136_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_V6K); set_feature(&cpu->env, ARM_FEATURE_V6); set_feature(&cpu->env, ARM_FEATURE_VFP); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); + set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG); + set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS); cpu->midr = ARM_CPUID_ARM1136; cpu->reset_fpsid = 0x410120b4; cpu->mvfr0 = 0x11111111; @@ -312,6 +323,9 @@ static void arm1176_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_V6K); set_feature(&cpu->env, ARM_FEATURE_VFP); set_feature(&cpu->env, ARM_FEATURE_VAPA); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); + set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG); + set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS); cpu->midr = ARM_CPUID_ARM1176; cpu->reset_fpsid = 0x410120b5; cpu->mvfr0 = 0x11111111; @@ -338,6 +352,7 @@ static void arm11mpcore_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_V6K); set_feature(&cpu->env, ARM_FEATURE_VFP); set_feature(&cpu->env, ARM_FEATURE_VAPA); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); cpu->midr = ARM_CPUID_ARM11MPCORE; cpu->reset_fpsid = 0x410120b4; cpu->mvfr0 = 0x11111111; @@ -372,6 +387,7 @@ static void cortex_a8_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_VFP3); set_feature(&cpu->env, ARM_FEATURE_NEON); set_feature(&cpu->env, ARM_FEATURE_THUMB2EE); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); cpu->midr = ARM_CPUID_CORTEXA8; cpu->reset_fpsid = 0x410330c0; cpu->mvfr0 = 0x11110222; @@ -483,6 +499,7 @@ static void cortex_a15_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_ARM_DIV); set_feature(&cpu->env, ARM_FEATURE_V7MP); set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); cpu->midr = ARM_CPUID_CORTEXA15; cpu->reset_fpsid = 0x410430f0; cpu->mvfr0 = 0x10110222; @@ -522,6 +539,7 @@ static void sa1100_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); set_feature(&cpu->env, ARM_FEATURE_STRONGARM); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); cpu->midr = ARM_CPUID_SA1100; cpu->reset_sctlr = 0x00000070; } @@ -530,6 +548,7 @@ static void sa1110_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); set_feature(&cpu->env, ARM_FEATURE_STRONGARM); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); cpu->midr = ARM_CPUID_SA1110; cpu->reset_sctlr = 0x00000070; } diff --git a/target-arm/cpu.h b/target-arm/cpu.h index b94503d774..02d86ca8aa 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -387,6 +387,9 @@ enum arm_features { ARM_FEATURE_GENERIC_TIMER, ARM_FEATURE_MVFR, /* Media and VFP Feature Registers 0 and 1 */ ARM_FEATURE_DUMMY_C15_REGS, /* RAZ/WI all of cp15 crn=15 */ + ARM_FEATURE_CACHE_TEST_CLEAN, /* 926/1026 style test-and-clean ops */ + ARM_FEATURE_CACHE_DIRTY_REG, /* 1136/1176 cache dirty status register */ + ARM_FEATURE_CACHE_BLOCK_OPS, /* v6 optional cache block operations */ }; static inline int arm_feature(CPUARMState *env, int feature) diff --git a/target-arm/helper.c b/target-arm/helper.c index b7fc2dbf0f..907ccbf9e6 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -161,6 +161,10 @@ static const ARMCPRegInfo cp_reginfo[] = { .opc1 = CP_ANY, .opc2 = 2, .access = PL1_W, .writefn = tlbiasid_write, }, { .name = "TLBIMVAA", .cp = 15, .crn = 8, .crm = CP_ANY, .opc1 = CP_ANY, .opc2 = 3, .access = PL1_W, .writefn = tlbimvaa_write, }, + /* Cache maintenance ops; some of this space may be overridden later. */ + { .name = "CACHEMAINT", .cp = 15, .crn = 7, .crm = CP_ANY, + .opc1 = 0, .opc2 = CP_ANY, .access = PL1_W, + .type = ARM_CP_NOP | ARM_CP_OVERRIDE }, REGINFO_SENTINEL }; @@ -622,6 +626,17 @@ static int omap_wfi_write(CPUARMState *env, const ARMCPRegInfo *ri, return 0; } +static int omap_cachemaint_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + /* On OMAP there are registers indicating the max/min index of dcache lines + * containing a dirty line; cache flush operations have to reset these. + */ + env->cp15.c15_i_max = 0x000; + env->cp15.c15_i_min = 0xff0; + return 0; +} + static const ARMCPRegInfo omap_cp_reginfo[] = { { .name = "DFSR", .cp = 15, .crn = 5, .crm = CP_ANY, .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_RW, .type = ARM_CP_OVERRIDE, @@ -650,6 +665,9 @@ static const ARMCPRegInfo omap_cp_reginfo[] = { * base address at $rn & ~0xfff and map size of 0x200 << ($rn & 0xfff), * when MMU is off. */ + { .name = "OMAP_CACHEMAINT", .cp = 15, .crn = 7, .crm = CP_ANY, + .opc1 = 0, .opc2 = CP_ANY, .access = PL1_W, .type = ARM_CP_OVERRIDE, + .writefn = omap_cachemaint_write }, REGINFO_SENTINEL }; @@ -685,6 +703,31 @@ static const ARMCPRegInfo dummy_c15_cp_reginfo[] = { REGINFO_SENTINEL }; +static const ARMCPRegInfo cache_dirty_status_cp_reginfo[] = { + /* Cache status: RAZ because we have no cache so it's always clean */ + { .name = "CDSR", .cp = 15, .crn = 7, .crm = 10, .opc1 = 0, .opc2 = 6, + .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 }, + REGINFO_SENTINEL +}; + +static const ARMCPRegInfo cache_block_ops_cp_reginfo[] = { + /* We never have a a block transfer operation in progress */ + { .name = "BXSR", .cp = 15, .crn = 7, .crm = 12, .opc1 = 0, .opc2 = 4, + .access = PL0_R, .type = ARM_CP_CONST, .resetvalue = 0 }, + REGINFO_SENTINEL +}; + +static const ARMCPRegInfo cache_test_clean_cp_reginfo[] = { + /* The cache test-and-clean instructions always return (1 << 30) + * to indicate that there are no dirty cache lines. + */ + { .name = "TC_DCACHE", .cp = 15, .crn = 7, .crm = 10, .opc1 = 0, .opc2 = 3, + .access = PL0_R, .type = ARM_CP_CONST, .resetvalue = (1 << 30) }, + { .name = "TCI_DCACHE", .cp = 15, .crn = 7, .crm = 14, .opc1 = 0, .opc2 = 3, + .access = PL0_R, .type = ARM_CP_CONST, .resetvalue = (1 << 30) }, + REGINFO_SENTINEL +}; + void register_cp_regs_for_features(ARMCPU *cpu) { /* Register all the coprocessor registers based on feature bits */ @@ -738,6 +781,15 @@ void register_cp_regs_for_features(ARMCPU *cpu) if (arm_feature(env, ARM_FEATURE_VAPA)) { define_arm_cp_regs(cpu, vapa_cp_reginfo); } + if (arm_feature(env, ARM_FEATURE_CACHE_TEST_CLEAN)) { + define_arm_cp_regs(cpu, cache_test_clean_cp_reginfo); + } + if (arm_feature(env, ARM_FEATURE_CACHE_DIRTY_REG)) { + define_arm_cp_regs(cpu, cache_dirty_status_cp_reginfo); + } + if (arm_feature(env, ARM_FEATURE_CACHE_BLOCK_OPS)) { + define_arm_cp_regs(cpu, cache_block_ops_cp_reginfo); + } if (arm_feature(env, ARM_FEATURE_OMAPCP)) { define_arm_cp_regs(cpu, omap_cp_reginfo); } @@ -1896,13 +1948,6 @@ void HELPER(set_cp15)(CPUARMState *env, uint32_t insn, uint32_t val) } } break; - case 7: /* Cache control. */ - env->cp15.c15_i_max = 0x000; - env->cp15.c15_i_min = 0xff0; - if (op1 != 0) { - goto bad_reg; - } - break; case 9: if (arm_feature(env, ARM_FEATURE_OMAPCP)) break; @@ -2108,10 +2153,6 @@ uint32_t HELPER(get_cp15)(CPUARMState *env, uint32_t insn) goto bad_reg; } } - case 7: /* Cache control. */ - /* FIXME: Should only clear Z flag if destination is r15. */ - env->ZF = 0; - return 0; case 9: switch (crm) { case 0: /* Cache lockdown */ -- cgit v1.2.3 From 06d76f319f2ea1cf8a66392670a04f649d6280ce Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jun 2012 11:57:17 +0000 Subject: target-arm: Convert cp15 crn=6 registers Convert the cp15 crn=6 registers to the new scheme. Note that this includes some minor tidyup: drop an unnecessary underdecoding of op2 on OMAPCP cores, and only implement the pre-v6 c6,c0,0,1 IFAR on the 1026 and not on the other ARMv5 cores, which didn't have it. Signed-off-by: Peter Maydell --- target-arm/cpu.c | 10 ++++++ target-arm/helper.c | 88 +++++++++++++++++++++-------------------------------- 2 files changed, 45 insertions(+), 53 deletions(-) diff --git a/target-arm/cpu.c b/target-arm/cpu.c index f8534a78b3..f37380ffe1 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -251,6 +251,16 @@ static void arm1026_initfn(Object *obj) cpu->reset_fpsid = 0x410110a0; cpu->ctr = 0x1dd20d2; cpu->reset_sctlr = 0x00090078; + { + /* The 1026 had an IFAR at c6,c0,0,1 rather than the ARMv6 c6,c0,0,2 */ + ARMCPRegInfo ifar = { + .name = "IFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 1, + .access = PL1_RW, + .fieldoffset = offsetof(CPUARMState, cp15.c6_insn), + .resetvalue = 0 + }; + define_one_arm_cp_reg(cpu, &ifar); + } } static void arm1136_r2_initfn(Object *obj) diff --git a/target-arm/helper.c b/target-arm/helper.c index 907ccbf9e6..5b77453858 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -197,6 +197,14 @@ static const ARMCPRegInfo v6_cp_reginfo[] = { .access = PL0_W, .type = ARM_CP_NOP }, { .name = "ISB", .cp = 15, .crn = 7, .crm = 10, .opc1 = 0, .opc2 = 5, .access = PL0_W, .type = ARM_CP_NOP }, + { .name = "IFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 2, + .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c6_insn), + .resetvalue = 0, }, + /* Watchpoint Fault Address Register : should actually only be present + * for 1136, 1176, 11MPCore. + */ + { .name = "WFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 1, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0, }, REGINFO_SENTINEL }; @@ -540,6 +548,26 @@ static int pmsav5_insn_ap_read(CPUARMState *env, const ARMCPRegInfo *ri, return 0; } +static int arm946_prbs_read(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t *value) +{ + if (ri->crm > 8) { + return EXCP_UDEF; + } + *value = env->cp15.c6_region[ri->crm]; + return 0; +} + +static int arm946_prbs_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + if (ri->crm > 8) { + return EXCP_UDEF; + } + env->cp15.c6_region[ri->crm] = value; + return 0; +} + static const ARMCPRegInfo pmsav5_cp_reginfo[] = { { .name = "DATA_AP", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 0, .access = PL1_RW, @@ -561,6 +589,10 @@ static const ARMCPRegInfo pmsav5_cp_reginfo[] = { { .name = "ICACHE_CFG", .cp = 15, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 1, .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c2_insn), .resetvalue = 0, }, + /* Protection region base and size registers */ + { .name = "946_PRBS", .cp = 15, .crn = 6, .crm = CP_ANY, .opc1 = 0, + .opc2 = CP_ANY, .access = PL1_RW, + .readfn = arm946_prbs_read, .writefn = arm946_prbs_write, }, REGINFO_SENTINEL }; @@ -598,6 +630,9 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = { .access = PL1_RW, .writefn = vmsa_ttbcr_write, .resetfn = vmsa_ttbcr_reset, .fieldoffset = offsetof(CPUARMState, cp15.c2_control) }, + { .name = "DFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c6_data), + .resetvalue = 0, }, REGINFO_SENTINEL }; @@ -1927,27 +1962,6 @@ void HELPER(set_cp15)(CPUARMState *env, uint32_t insn, uint32_t val) break; case 4: /* Reserved. */ goto bad_reg; - case 6: /* MMU Fault address / MPU base/size. */ - if (arm_feature(env, ARM_FEATURE_MPU)) { - if (crm >= 8) - goto bad_reg; - env->cp15.c6_region[crm] = val; - } else { - if (arm_feature(env, ARM_FEATURE_OMAPCP)) - op2 = 0; - switch (op2) { - case 0: - env->cp15.c6_data = val; - break; - case 1: /* ??? This is WFAR on armv6 */ - case 2: - env->cp15.c6_insn = val; - break; - default: - goto bad_reg; - } - } - break; case 9: if (arm_feature(env, ARM_FEATURE_OMAPCP)) break; @@ -2121,38 +2135,6 @@ uint32_t HELPER(get_cp15)(CPUARMState *env, uint32_t insn) } case 4: /* Reserved. */ goto bad_reg; - case 6: /* MMU Fault address. */ - if (arm_feature(env, ARM_FEATURE_MPU)) { - if (crm >= 8) - goto bad_reg; - return env->cp15.c6_region[crm]; - } else { - if (arm_feature(env, ARM_FEATURE_OMAPCP)) - op2 = 0; - switch (op2) { - case 0: - return env->cp15.c6_data; - case 1: - if (arm_feature(env, ARM_FEATURE_V6)) { - /* Watchpoint Fault Adrress. */ - return 0; /* Not implemented. */ - } else { - /* Instruction Fault Adrress. */ - /* Arm9 doesn't have an IFAR, but implementing it anyway - shouldn't do any harm. */ - return env->cp15.c6_insn; - } - case 2: - if (arm_feature(env, ARM_FEATURE_V6)) { - /* Instruction Fault Adrress. */ - return env->cp15.c6_insn; - } else { - goto bad_reg; - } - default: - goto bad_reg; - } - } case 9: switch (crm) { case 0: /* Cache lockdown */ -- cgit v1.2.3 From 34f9052967b2495c524560906023dbebf6556b5d Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jun 2012 11:57:18 +0000 Subject: target-arm: Convert cp15 crn=9 registers Convert cp15 crn=9 registers (mostly cache lockdown) to the new scheme. Note that this change makes OMAPCP cores RAZ/WI the whole c9 space. This is a change from previous behaviour, but a return to the behaviour of commit c3d2689d when OMAP1 support was first added -- subsequent commits have clearly accidentally relegated the OMAPCP RAZ condition to only a subset of the crn=9 space when adding support for other cores. Signed-off-by: Peter Maydell --- target-arm/cpu.c | 34 +++++++++++++++++ target-arm/helper.c | 104 +++++++++++++--------------------------------------- 2 files changed, 59 insertions(+), 79 deletions(-) diff --git a/target-arm/cpu.c b/target-arm/cpu.c index f37380ffe1..c03db20820 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -23,6 +23,7 @@ #if !defined(CONFIG_USER_ONLY) #include "hw/loader.h" #endif +#include "sysemu.h" static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque) { @@ -390,6 +391,14 @@ static void cortex_m3_initfn(Object *obj) cpu->midr = ARM_CPUID_CORTEXM3; } +static const ARMCPRegInfo cortexa8_cp_reginfo[] = { + { .name = "L2LOCKDOWN", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "L2AUXCR", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 2, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + REGINFO_SENTINEL +}; + static void cortex_a8_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); @@ -421,6 +430,7 @@ static void cortex_a8_initfn(Object *obj) cpu->ccsidr[0] = 0xe007e01a; /* 16k L1 dcache. */ cpu->ccsidr[1] = 0x2007e01a; /* 16k L1 icache. */ cpu->ccsidr[2] = 0xf0000000; /* No L2 icache. */ + define_arm_cp_regs(cpu, cortexa8_cp_reginfo); } static const ARMCPRegInfo cortexa9_cp_reginfo[] = { @@ -498,6 +508,29 @@ static void cortex_a9_initfn(Object *obj) } } +#ifndef CONFIG_USER_ONLY +static int a15_l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t *value) +{ + /* Linux wants the number of processors from here. + * Might as well set the interrupt-controller bit too. + */ + *value = ((smp_cpus - 1) << 24) | (1 << 23); + return 0; +} +#endif + +static const ARMCPRegInfo cortexa15_cp_reginfo[] = { +#ifndef CONFIG_USER_ONLY + { .name = "L2CTLR", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 2, + .access = PL1_RW, .resetvalue = 0, .readfn = a15_l2ctlr_read, + .writefn = arm_cp_write_ignore, }, +#endif + { .name = "L2ECTLR", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 3, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + REGINFO_SENTINEL +}; + static void cortex_a15_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); @@ -533,6 +566,7 @@ static void cortex_a15_initfn(Object *obj) cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */ cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */ cpu->ccsidr[2] = 0x711fe07a; /* 4096K L2 unified cache */ + define_arm_cp_regs(cpu, cortexa15_cp_reginfo); } static void ti925t_initfn(Object *obj) diff --git a/target-arm/helper.c b/target-arm/helper.c index 5b77453858..2c6e7ed7d5 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -183,6 +183,16 @@ static const ARMCPRegInfo not_v7_cp_reginfo[] = { */ { .name = "WFI_v6", .cp = 15, .crn = 7, .crm = 0, .opc1 = 0, .opc2 = 4, .access = PL1_W, .type = ARM_CP_WFI }, + /* L1 cache lockdown. Not architectural in v6 and earlier but in practice + * implemented in 926, 946, 1026, 1136, 1176 and 11MPCore. StrongARM and + * OMAPCP will override this space. + */ + { .name = "DLOCKDOWN", .cp = 15, .crn = 9, .crm = 0, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c9_data), + .resetvalue = 0 }, + { .name = "ILOCKDOWN", .cp = 15, .crn = 9, .crm = 0, .opc1 = 0, .opc2 = 1, + .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c9_insn), + .resetvalue = 0 }, REGINFO_SENTINEL }; @@ -703,6 +713,9 @@ static const ARMCPRegInfo omap_cp_reginfo[] = { { .name = "OMAP_CACHEMAINT", .cp = 15, .crn = 7, .crm = CP_ANY, .opc1 = 0, .opc2 = CP_ANY, .access = PL1_W, .type = ARM_CP_OVERRIDE, .writefn = omap_cachemaint_write }, + { .name = "C9", .cp = 15, .crn = 9, + .crm = CP_ANY, .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_RW, + .type = ARM_CP_CONST | ARM_CP_OVERRIDE, .resetvalue = 0 }, REGINFO_SENTINEL }; @@ -763,6 +776,15 @@ static const ARMCPRegInfo cache_test_clean_cp_reginfo[] = { REGINFO_SENTINEL }; +static const ARMCPRegInfo strongarm_cp_reginfo[] = { + /* Ignore ReadBuffer accesses */ + { .name = "C9_READBUFFER", .cp = 15, .crn = 9, + .crm = CP_ANY, .opc1 = CP_ANY, .opc2 = CP_ANY, + .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_OVERRIDE, + .resetvalue = 0 }, + REGINFO_SENTINEL +}; + void register_cp_regs_for_features(ARMCPU *cpu) { /* Register all the coprocessor registers based on feature bits */ @@ -828,6 +850,9 @@ void register_cp_regs_for_features(ARMCPU *cpu) if (arm_feature(env, ARM_FEATURE_OMAPCP)) { define_arm_cp_regs(cpu, omap_cp_reginfo); } + if (arm_feature(env, ARM_FEATURE_STRONGARM)) { + define_arm_cp_regs(cpu, strongarm_cp_reginfo); + } if (arm_feature(env, ARM_FEATURE_XSCALE)) { define_arm_cp_regs(cpu, xscale_cp_reginfo); } @@ -1962,40 +1987,6 @@ void HELPER(set_cp15)(CPUARMState *env, uint32_t insn, uint32_t val) break; case 4: /* Reserved. */ goto bad_reg; - case 9: - if (arm_feature(env, ARM_FEATURE_OMAPCP)) - break; - if (arm_feature(env, ARM_FEATURE_STRONGARM)) - break; /* Ignore ReadBuffer access */ - switch (crm) { - case 0: /* Cache lockdown. */ - switch (op1) { - case 0: /* L1 cache. */ - switch (op2) { - case 0: - env->cp15.c9_data = val; - break; - case 1: - env->cp15.c9_insn = val; - break; - default: - goto bad_reg; - } - break; - case 1: /* L2 cache. */ - /* Ignore writes to L2 lockdown/auxiliary registers. */ - break; - default: - goto bad_reg; - } - break; - case 1: /* TCM memory region registers. */ - /* Not implemented. */ - goto bad_reg; - default: - goto bad_reg; - } - break; case 12: /* Reserved. */ goto bad_reg; } @@ -2135,51 +2126,6 @@ uint32_t HELPER(get_cp15)(CPUARMState *env, uint32_t insn) } case 4: /* Reserved. */ goto bad_reg; - case 9: - switch (crm) { - case 0: /* Cache lockdown */ - switch (op1) { - case 0: /* L1 cache. */ - if (arm_feature(env, ARM_FEATURE_OMAPCP)) { - return 0; - } - switch (op2) { - case 0: - return env->cp15.c9_data; - case 1: - return env->cp15.c9_insn; - default: - goto bad_reg; - } - case 1: /* L2 cache */ - /* L2 Lockdown and Auxiliary control. */ - switch (op2) { - case 0: - /* L2 cache lockdown (A8 only) */ - return 0; - case 2: - /* L2 cache auxiliary control (A8) or control (A15) */ - if (ARM_CPUID(env) == ARM_CPUID_CORTEXA15) { - /* Linux wants the number of processors from here. - * Might as well set the interrupt-controller bit too. - */ - return ((smp_cpus - 1) << 24) | (1 << 23); - } - return 0; - case 3: - /* L2 cache extended control (A15) */ - return 0; - default: - goto bad_reg; - } - default: - goto bad_reg; - } - break; - default: - goto bad_reg; - } - break; case 11: /* TCM DMA control. */ case 12: /* Reserved. */ goto bad_reg; -- cgit v1.2.3 From 2771db274193420b82f988b995282820631cdd99 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jun 2012 11:57:18 +0000 Subject: target-arm: Convert cp15 crn=1 registers Convert the cp15 crn=1 registers to the new scheme. Signed-off-by: Peter Maydell --- target-arm/cpu-qom.h | 1 + target-arm/cpu.c | 7 ++- target-arm/helper.c | 129 +++++++++++++++++++++------------------------------ 3 files changed, 61 insertions(+), 76 deletions(-) diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h index 4ccfc897c2..beabf9a0a9 100644 --- a/target-arm/cpu-qom.h +++ b/target-arm/cpu-qom.h @@ -97,6 +97,7 @@ typedef struct ARMCPU { */ uint32_t ccsidr[16]; uint32_t reset_cbar; + uint32_t reset_auxcr; } ARMCPU; static inline ARMCPU *arm_env_get_cpu(CPUARMState *env) diff --git a/target-arm/cpu.c b/target-arm/cpu.c index c03db20820..d84db53fab 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -77,7 +77,6 @@ static void arm_cpu_reset(CPUState *s) env->vfp.xregs[ARM_VFP_MVFR0] = cpu->mvfr0; env->vfp.xregs[ARM_VFP_MVFR1] = cpu->mvfr1; env->cp15.c0_cachetype = cpu->ctr; - env->cp15.c1_sys = cpu->reset_sctlr; env->cp15.c0_c1[0] = cpu->id_pfr0; env->cp15.c0_c1[1] = cpu->id_pfr1; env->cp15.c0_c1[2] = cpu->id_dfr0; @@ -252,6 +251,7 @@ static void arm1026_initfn(Object *obj) cpu->reset_fpsid = 0x410110a0; cpu->ctr = 0x1dd20d2; cpu->reset_sctlr = 0x00090078; + cpu->reset_auxcr = 1; { /* The 1026 had an IFAR at c6,c0,0,1 rather than the ARMv6 c6,c0,0,2 */ ARMCPRegInfo ifar = { @@ -297,6 +297,7 @@ static void arm1136_r2_initfn(Object *obj) cpu->id_isar2 = 0x11231111; cpu->id_isar3 = 0x01102131; cpu->id_isar4 = 0x141; + cpu->reset_auxcr = 7; } static void arm1136_initfn(Object *obj) @@ -326,6 +327,7 @@ static void arm1136_initfn(Object *obj) cpu->id_isar2 = 0x11231111; cpu->id_isar3 = 0x01102131; cpu->id_isar4 = 0x141; + cpu->reset_auxcr = 7; } static void arm1176_initfn(Object *obj) @@ -355,6 +357,7 @@ static void arm1176_initfn(Object *obj) cpu->id_isar2 = 0x11231121; cpu->id_isar3 = 0x01102131; cpu->id_isar4 = 0x01141; + cpu->reset_auxcr = 7; } static void arm11mpcore_initfn(Object *obj) @@ -381,6 +384,7 @@ static void arm11mpcore_initfn(Object *obj) cpu->id_isar2 = 0x11221011; cpu->id_isar3 = 0x01102131; cpu->id_isar4 = 0x141; + cpu->reset_auxcr = 1; } static void cortex_m3_initfn(Object *obj) @@ -430,6 +434,7 @@ static void cortex_a8_initfn(Object *obj) cpu->ccsidr[0] = 0xe007e01a; /* 16k L1 dcache. */ cpu->ccsidr[1] = 0x2007e01a; /* 16k L1 icache. */ cpu->ccsidr[2] = 0xf0000000; /* No L2 icache. */ + cpu->reset_auxcr = 2; define_arm_cp_regs(cpu, cortexa8_cp_reginfo); } diff --git a/target-arm/helper.c b/target-arm/helper.c index 2c6e7ed7d5..00934cdf37 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -196,6 +196,16 @@ static const ARMCPRegInfo not_v7_cp_reginfo[] = { REGINFO_SENTINEL }; +static int cpacr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) +{ + if (env->cp15.c1_coproc != value) { + env->cp15.c1_coproc = value; + /* ??? Is this safe when called from within a TB? */ + tb_flush(env); + } + return 0; +} + static const ARMCPRegInfo v6_cp_reginfo[] = { /* prefetch by MVA in v6, NOP in v7 */ { .name = "MVA_prefetch", @@ -215,6 +225,9 @@ static const ARMCPRegInfo v6_cp_reginfo[] = { */ { .name = "WFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 1, .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0, }, + { .name = "CPACR", .cp = 15, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 2, + .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_coproc), + .resetvalue = 0, .writefn = cpacr_write }, REGINFO_SENTINEL }; @@ -376,6 +389,9 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { .fieldoffset = offsetof(CPUARMState, cp15.c9_pminten), .resetvalue = 0, .writefn = pmintenclr_write }, + { .name = "SCR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_scr), + .resetvalue = 0, }, REGINFO_SENTINEL }; @@ -736,6 +752,10 @@ static const ARMCPRegInfo xscale_cp_reginfo[] = { .cp = 15, .crn = 15, .crm = 1, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c15_cpar), .resetvalue = 0, .writefn = xscale_cpar_write, }, + { .name = "XSCALE_AUXCR", + .cp = 15, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 1, .access = PL1_RW, + .fieldoffset = offsetof(CPUARMState, cp15.c1_xscaleauxcr), + .resetvalue = 0, }, REGINFO_SENTINEL }; @@ -785,6 +805,15 @@ static const ARMCPRegInfo strongarm_cp_reginfo[] = { REGINFO_SENTINEL }; +static int sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) +{ + env->cp15.c1_sys = value; + /* ??? Lots of these bits are not implemented. */ + /* This may enable/disable the MMU, so do a TLB flush. */ + tlb_flush(env, 1); + return 0; +} + void register_cp_regs_for_features(ARMCPU *cpu) { /* Register all the coprocessor registers based on feature bits */ @@ -859,6 +888,31 @@ void register_cp_regs_for_features(ARMCPU *cpu) if (arm_feature(env, ARM_FEATURE_DUMMY_C15_REGS)) { define_arm_cp_regs(cpu, dummy_c15_cp_reginfo); } + if (arm_feature(env, ARM_FEATURE_AUXCR)) { + ARMCPRegInfo auxcr = { + .name = "AUXCR", .cp = 15, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 1, + .access = PL1_RW, .type = ARM_CP_CONST, + .resetvalue = cpu->reset_auxcr + }; + define_one_arm_cp_reg(cpu, &auxcr); + } + + /* Generic registers whose values depend on the implementation */ + { + ARMCPRegInfo sctlr = { + .name = "SCTLR", .cp = 15, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_sys), + .writefn = sctlr_write, .resetvalue = cpu->reset_sctlr + }; + if (arm_feature(env, ARM_FEATURE_XSCALE)) { + /* Normally we would always end the TB on an SCTLR write, but Linux + * arch/arm/mach-pxa/sleep.S expects two instructions following + * an MMU enable to execute from cache. Imitate this behaviour. + */ + sctlr.type |= ARM_CP_SUPPRESS_TB_END; + } + define_one_arm_cp_reg(cpu, &sctlr); + } } ARMCPU *cpu_arm_init(const char *cpu_model) @@ -1949,42 +2003,6 @@ void HELPER(set_cp15)(CPUARMState *env, uint32_t insn, uint32_t val) break; } goto bad_reg; - case 1: /* System configuration. */ - if (arm_feature(env, ARM_FEATURE_V7) - && op1 == 0 && crm == 1 && op2 == 0) { - env->cp15.c1_scr = val; - break; - } - if (arm_feature(env, ARM_FEATURE_OMAPCP)) - op2 = 0; - switch (op2) { - case 0: - if (!arm_feature(env, ARM_FEATURE_XSCALE) || crm == 0) - env->cp15.c1_sys = val; - /* ??? Lots of these bits are not implemented. */ - /* This may enable/disable the MMU, so do a TLB flush. */ - tlb_flush(env, 1); - break; - case 1: /* Auxiliary control register. */ - if (arm_feature(env, ARM_FEATURE_XSCALE)) { - env->cp15.c1_xscaleauxcr = val; - break; - } - /* Not implemented. */ - break; - case 2: - if (arm_feature(env, ARM_FEATURE_XSCALE)) - goto bad_reg; - if (env->cp15.c1_coproc != val) { - env->cp15.c1_coproc = val; - /* ??? Is this safe when called from within a TB? */ - tb_flush(env); - } - break; - default: - goto bad_reg; - } - break; case 4: /* Reserved. */ goto bad_reg; case 12: /* Reserved. */ @@ -2085,45 +2103,6 @@ uint32_t HELPER(get_cp15)(CPUARMState *env, uint32_t insn) default: goto bad_reg; } - case 1: /* System configuration. */ - if (arm_feature(env, ARM_FEATURE_V7) - && op1 == 0 && crm == 1 && op2 == 0) { - return env->cp15.c1_scr; - } - if (arm_feature(env, ARM_FEATURE_OMAPCP)) - op2 = 0; - switch (op2) { - case 0: /* Control register. */ - return env->cp15.c1_sys; - case 1: /* Auxiliary control register. */ - if (arm_feature(env, ARM_FEATURE_XSCALE)) - return env->cp15.c1_xscaleauxcr; - if (!arm_feature(env, ARM_FEATURE_AUXCR)) - goto bad_reg; - switch (ARM_CPUID(env)) { - case ARM_CPUID_ARM1026: - return 1; - case ARM_CPUID_ARM1136: - case ARM_CPUID_ARM1136_R2: - case ARM_CPUID_ARM1176: - return 7; - case ARM_CPUID_ARM11MPCORE: - return 1; - case ARM_CPUID_CORTEXA8: - return 2; - case ARM_CPUID_CORTEXA9: - case ARM_CPUID_CORTEXA15: - return 0; - default: - goto bad_reg; - } - case 2: /* Coprocessor access register. */ - if (arm_feature(env, ARM_FEATURE_XSCALE)) - goto bad_reg; - return env->cp15.c1_coproc; - default: - goto bad_reg; - } case 4: /* Reserved. */ goto bad_reg; case 11: /* TCM DMA control. */ -- cgit v1.2.3 From 8515a092948584ce112b90030edcef344c6a0f90 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jun 2012 11:57:19 +0000 Subject: target-arm: Convert cp15 crn=0 crm={1,2} feature registers Convert the cp15 crn=0 crm={1,2} features registers to the new cp reg framework. Signed-off-by: Peter Maydell --- target-arm/cpu.c | 14 ------------ target-arm/cpu.h | 2 -- target-arm/helper.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 54 insertions(+), 24 deletions(-) diff --git a/target-arm/cpu.c b/target-arm/cpu.c index d84db53fab..f9b3046bba 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -77,20 +77,6 @@ static void arm_cpu_reset(CPUState *s) env->vfp.xregs[ARM_VFP_MVFR0] = cpu->mvfr0; env->vfp.xregs[ARM_VFP_MVFR1] = cpu->mvfr1; env->cp15.c0_cachetype = cpu->ctr; - env->cp15.c0_c1[0] = cpu->id_pfr0; - env->cp15.c0_c1[1] = cpu->id_pfr1; - env->cp15.c0_c1[2] = cpu->id_dfr0; - env->cp15.c0_c1[3] = cpu->id_afr0; - env->cp15.c0_c1[4] = cpu->id_mmfr0; - env->cp15.c0_c1[5] = cpu->id_mmfr1; - env->cp15.c0_c1[6] = cpu->id_mmfr2; - env->cp15.c0_c1[7] = cpu->id_mmfr3; - env->cp15.c0_c2[0] = cpu->id_isar0; - env->cp15.c0_c2[1] = cpu->id_isar1; - env->cp15.c0_c2[2] = cpu->id_isar2; - env->cp15.c0_c2[3] = cpu->id_isar3; - env->cp15.c0_c2[4] = cpu->id_isar4; - env->cp15.c0_c2[5] = cpu->id_isar5; env->cp15.c0_clid = cpu->clidr; memcpy(env->cp15.c0_ccsid, cpu->ccsidr, ARRAY_SIZE(cpu->ccsidr)); diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 02d86ca8aa..095354304a 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -111,8 +111,6 @@ typedef struct CPUARMState { uint32_t c0_ccsid[16]; /* Cache size. */ uint32_t c0_clid; /* Cache level. */ uint32_t c0_cssel; /* Cache size selection. */ - uint32_t c0_c1[8]; /* Feature registers. */ - uint32_t c0_c2[8]; /* Instruction set registers. */ uint32_t c1_sys; /* System control register. */ uint32_t c1_coproc; /* Coprocessor access register. */ uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */ diff --git a/target-arm/helper.c b/target-arm/helper.c index 00934cdf37..11b2ad94fb 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -825,6 +825,60 @@ void register_cp_regs_for_features(ARMCPU *cpu) define_arm_cp_regs(cpu, cp_reginfo); if (arm_feature(env, ARM_FEATURE_V6)) { + /* The ID registers all have impdef reset values */ + ARMCPRegInfo v6_idregs[] = { + { .name = "ID_PFR0", .cp = 15, .crn = 0, .crm = 1, + .opc1 = 0, .opc2 = 0, .access = PL1_R, .type = ARM_CP_CONST, + .resetvalue = cpu->id_pfr0 }, + { .name = "ID_PFR1", .cp = 15, .crn = 0, .crm = 1, + .opc1 = 0, .opc2 = 1, .access = PL1_R, .type = ARM_CP_CONST, + .resetvalue = cpu->id_pfr1 }, + { .name = "ID_DFR0", .cp = 15, .crn = 0, .crm = 1, + .opc1 = 0, .opc2 = 2, .access = PL1_R, .type = ARM_CP_CONST, + .resetvalue = cpu->id_dfr0 }, + { .name = "ID_AFR0", .cp = 15, .crn = 0, .crm = 1, + .opc1 = 0, .opc2 = 3, .access = PL1_R, .type = ARM_CP_CONST, + .resetvalue = cpu->id_afr0 }, + { .name = "ID_MMFR0", .cp = 15, .crn = 0, .crm = 1, + .opc1 = 0, .opc2 = 4, .access = PL1_R, .type = ARM_CP_CONST, + .resetvalue = cpu->id_mmfr0 }, + { .name = "ID_MMFR1", .cp = 15, .crn = 0, .crm = 1, + .opc1 = 0, .opc2 = 5, .access = PL1_R, .type = ARM_CP_CONST, + .resetvalue = cpu->id_mmfr1 }, + { .name = "ID_MMFR2", .cp = 15, .crn = 0, .crm = 1, + .opc1 = 0, .opc2 = 6, .access = PL1_R, .type = ARM_CP_CONST, + .resetvalue = cpu->id_mmfr2 }, + { .name = "ID_MMFR3", .cp = 15, .crn = 0, .crm = 1, + .opc1 = 0, .opc2 = 7, .access = PL1_R, .type = ARM_CP_CONST, + .resetvalue = cpu->id_mmfr3 }, + { .name = "ID_ISAR0", .cp = 15, .crn = 0, .crm = 2, + .opc1 = 0, .opc2 = 0, .access = PL1_R, .type = ARM_CP_CONST, + .resetvalue = cpu->id_isar0 }, + { .name = "ID_ISAR1", .cp = 15, .crn = 0, .crm = 2, + .opc1 = 0, .opc2 = 1, .access = PL1_R, .type = ARM_CP_CONST, + .resetvalue = cpu->id_isar1 }, + { .name = "ID_ISAR2", .cp = 15, .crn = 0, .crm = 2, + .opc1 = 0, .opc2 = 2, .access = PL1_R, .type = ARM_CP_CONST, + .resetvalue = cpu->id_isar2 }, + { .name = "ID_ISAR3", .cp = 15, .crn = 0, .crm = 2, + .opc1 = 0, .opc2 = 3, .access = PL1_R, .type = ARM_CP_CONST, + .resetvalue = cpu->id_isar3 }, + { .name = "ID_ISAR4", .cp = 15, .crn = 0, .crm = 2, + .opc1 = 0, .opc2 = 4, .access = PL1_R, .type = ARM_CP_CONST, + .resetvalue = cpu->id_isar4 }, + { .name = "ID_ISAR5", .cp = 15, .crn = 0, .crm = 2, + .opc1 = 0, .opc2 = 5, .access = PL1_R, .type = ARM_CP_CONST, + .resetvalue = cpu->id_isar5 }, + /* 6..7 are as yet unallocated and must RAZ */ + { .name = "ID_ISAR6", .cp = 15, .crn = 0, .crm = 2, + .opc1 = 0, .opc2 = 6, .access = PL1_R, .type = ARM_CP_CONST, + .resetvalue = 0 }, + { .name = "ID_ISAR7", .cp = 15, .crn = 0, .crm = 2, + .opc1 = 0, .opc2 = 7, .access = PL1_R, .type = ARM_CP_CONST, + .resetvalue = 0 }, + REGINFO_SENTINEL + }; + define_arm_cp_regs(cpu, v6_idregs); define_arm_cp_regs(cpu, v6_cp_reginfo); } else { define_arm_cp_regs(cpu, not_v6_cp_reginfo); @@ -2064,14 +2118,6 @@ uint32_t HELPER(get_cp15)(CPUARMState *env, uint32_t insn) default: goto bad_reg; } - case 1: - if (!arm_feature(env, ARM_FEATURE_V6)) - goto bad_reg; - return env->cp15.c0_c1[op2]; - case 2: - if (!arm_feature(env, ARM_FEATURE_V6)) - goto bad_reg; - return env->cp15.c0_c2[op2]; case 3: case 4: case 5: case 6: case 7: return 0; default: -- cgit v1.2.3 From 776d4e5c6ca47f8d7b73c9c8eccf20209bf57529 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jun 2012 11:57:19 +0000 Subject: target-arm: Convert cp15 cache ID registers Convert the cp15 cache ID registers to the new scheme. Signed-off-by: Peter Maydell --- target-arm/cpu.c | 2 -- target-arm/cpu.h | 2 -- target-arm/helper.c | 61 +++++++++++++++++++++++++++++------------------------ 3 files changed, 33 insertions(+), 32 deletions(-) diff --git a/target-arm/cpu.c b/target-arm/cpu.c index f9b3046bba..f4c9116960 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -77,8 +77,6 @@ static void arm_cpu_reset(CPUState *s) env->vfp.xregs[ARM_VFP_MVFR0] = cpu->mvfr0; env->vfp.xregs[ARM_VFP_MVFR1] = cpu->mvfr1; env->cp15.c0_cachetype = cpu->ctr; - env->cp15.c0_clid = cpu->clidr; - memcpy(env->cp15.c0_ccsid, cpu->ccsidr, ARRAY_SIZE(cpu->ccsidr)); if (arm_feature(env, ARM_FEATURE_IWMMXT)) { env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q'; diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 095354304a..0b984d8495 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -108,8 +108,6 @@ typedef struct CPUARMState { struct { uint32_t c0_cpuid; uint32_t c0_cachetype; - uint32_t c0_ccsid[16]; /* Cache size. */ - uint32_t c0_clid; /* Cache level. */ uint32_t c0_cssel; /* Cache size selection. */ uint32_t c1_sys; /* System control register. */ uint32_t c1_coproc; /* Coprocessor access register. */ diff --git a/target-arm/helper.c b/target-arm/helper.c index 11b2ad94fb..269740d248 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -193,6 +193,9 @@ static const ARMCPRegInfo not_v7_cp_reginfo[] = { { .name = "ILOCKDOWN", .cp = 15, .crn = 9, .crm = 0, .opc1 = 0, .opc2 = 1, .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c9_insn), .resetvalue = 0 }, + /* v6 doesn't have the cache ID registers but Linux reads them anyway */ + { .name = "DUMMY", .cp = 15, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = CP_ANY, + .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 }, REGINFO_SENTINEL }; @@ -322,6 +325,21 @@ static int pmintenclr_write(CPUARMState *env, const ARMCPRegInfo *ri, return 0; } +static int ccsidr_read(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t *value) +{ + ARMCPU *cpu = arm_env_get_cpu(env); + *value = cpu->ccsidr[env->cp15.c0_cssel]; + return 0; +} + +static int csselr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + env->cp15.c0_cssel = value & 0xf; + return 0; +} + static const ARMCPRegInfo v7_cp_reginfo[] = { /* DBGDRAR, DBGDSAR: always RAZ since we don't implement memory mapped * debug components @@ -392,6 +410,16 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { { .name = "SCR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_scr), .resetvalue = 0, }, + { .name = "CCSIDR", .cp = 15, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 0, + .access = PL1_R, .readfn = ccsidr_read }, + { .name = "CSSELR", .cp = 15, .crn = 0, .crm = 0, .opc1 = 2, .opc2 = 0, + .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c0_cssel), + .writefn = csselr_write, .resetvalue = 0 }, + /* Auxiliary ID register: this actually has an IMPDEF value but for now + * just RAZ for all cores: + */ + { .name = "AIDR", .cp = 15, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 7, + .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 }, REGINFO_SENTINEL }; @@ -896,7 +924,12 @@ void register_cp_regs_for_features(ARMCPU *cpu) .fieldoffset = offsetof(CPUARMState, cp15.c9_pmcr), .readfn = pmreg_read, .writefn = pmcr_write }; + ARMCPRegInfo clidr = { + .name = "CLIDR", .cp = 15, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 1, + .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = cpu->clidr + }; define_one_arm_cp_reg(cpu, &pmcr); + define_one_arm_cp_reg(cpu, &clidr); define_arm_cp_regs(cpu, v7_cp_reginfo); } else { define_arm_cp_regs(cpu, not_v7_cp_reginfo); @@ -2051,11 +2084,6 @@ void HELPER(set_cp15)(CPUARMState *env, uint32_t insn, uint32_t val) break; if (arm_feature(env, ARM_FEATURE_OMAPCP)) break; - if (arm_feature(env, ARM_FEATURE_V7) - && op1 == 2 && crm == 0 && op2 == 0) { - env->cp15.c0_cssel = val & 0xf; - break; - } goto bad_reg; case 4: /* Reserved. */ goto bad_reg; @@ -2123,29 +2151,6 @@ uint32_t HELPER(get_cp15)(CPUARMState *env, uint32_t insn) default: goto bad_reg; } - case 1: - /* These registers aren't documented on arm11 cores. However - Linux looks at them anyway. */ - if (!arm_feature(env, ARM_FEATURE_V6)) - goto bad_reg; - if (crm != 0) - goto bad_reg; - if (!arm_feature(env, ARM_FEATURE_V7)) - return 0; - - switch (op2) { - case 0: - return env->cp15.c0_ccsid[env->cp15.c0_cssel]; - case 1: - return env->cp15.c0_clid; - case 7: - return 0; - } - goto bad_reg; - case 2: - if (op2 != 0 || crm != 0) - goto bad_reg; - return env->cp15.c0_cssel; default: goto bad_reg; } -- cgit v1.2.3 From 81bdde9dcdba5bbc358b2c6b8f776a05a751cc72 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jun 2012 11:57:20 +0000 Subject: target-arm: Convert MPIDR Convert the MPIDR to the new cp15 register scheme. This includes giving it its own feature bit rather than doing a CPUID value check. Signed-off-by: Peter Maydell --- target-arm/cpu.c | 2 ++ target-arm/cpu.h | 1 + target-arm/helper.c | 50 ++++++++++++++++++++++++++++---------------------- 3 files changed, 31 insertions(+), 22 deletions(-) diff --git a/target-arm/cpu.c b/target-arm/cpu.c index f4c9116960..0c031ba88b 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -162,6 +162,7 @@ void arm_cpu_realize(ARMCPU *cpu) if (arm_feature(env, ARM_FEATURE_V7)) { set_feature(env, ARM_FEATURE_VAPA); set_feature(env, ARM_FEATURE_THUMB2); + set_feature(env, ARM_FEATURE_MPIDR); if (!arm_feature(env, ARM_FEATURE_M)) { set_feature(env, ARM_FEATURE_V6K); } else { @@ -350,6 +351,7 @@ static void arm11mpcore_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_V6K); set_feature(&cpu->env, ARM_FEATURE_VFP); set_feature(&cpu->env, ARM_FEATURE_VAPA); + set_feature(&cpu->env, ARM_FEATURE_MPIDR); set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); cpu->midr = ARM_CPUID_ARM11MPCORE; cpu->reset_fpsid = 0x410120b4; diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 0b984d8495..2630fe7739 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -386,6 +386,7 @@ enum arm_features { ARM_FEATURE_CACHE_TEST_CLEAN, /* 926/1026 style test-and-clean ops */ ARM_FEATURE_CACHE_DIRTY_REG, /* 1136/1176 cache dirty status register */ ARM_FEATURE_CACHE_BLOCK_OPS, /* v6 optional cache block operations */ + ARM_FEATURE_MPIDR, /* has cp15 MPIDR */ }; static inline int arm_feature(CPUARMState *env, int feature) diff --git a/target-arm/helper.c b/target-arm/helper.c index 269740d248..1acc2128f0 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -833,6 +833,31 @@ static const ARMCPRegInfo strongarm_cp_reginfo[] = { REGINFO_SENTINEL }; +static int mpidr_read(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t *value) +{ + uint32_t mpidr = env->cpu_index; + /* We don't support setting cluster ID ([8..11]) + * so these bits always RAZ. + */ + if (arm_feature(env, ARM_FEATURE_V7MP)) { + mpidr |= (1 << 31); + /* Cores which are uniprocessor (non-coherent) + * but still implement the MP extensions set + * bit 30. (For instance, A9UP.) However we do + * not currently model any of those cores. + */ + } + *value = mpidr; + return 0; +} + +static const ARMCPRegInfo mpidr_cp_reginfo[] = { + { .name = "MPIDR", .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 5, + .access = PL1_R, .readfn = mpidr_read }, + REGINFO_SENTINEL +}; + static int sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { env->cp15.c1_sys = value; @@ -975,6 +1000,9 @@ void register_cp_regs_for_features(ARMCPU *cpu) if (arm_feature(env, ARM_FEATURE_DUMMY_C15_REGS)) { define_arm_cp_regs(cpu, dummy_c15_cp_reginfo); } + if (arm_feature(env, ARM_FEATURE_MPIDR)) { + define_arm_cp_regs(cpu, mpidr_cp_reginfo); + } if (arm_feature(env, ARM_FEATURE_AUXCR)) { ARMCPRegInfo auxcr = { .name = "AUXCR", .cp = 15, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 1, @@ -2121,28 +2149,6 @@ uint32_t HELPER(get_cp15)(CPUARMState *env, uint32_t insn) return 0; case 3: /* TLB type register. */ return 0; /* No lockable TLB entries. */ - case 5: /* MPIDR */ - /* The MPIDR was standardised in v7; prior to - * this it was implemented only in the 11MPCore. - * For all other pre-v7 cores it does not exist. - */ - if (arm_feature(env, ARM_FEATURE_V7) || - ARM_CPUID(env) == ARM_CPUID_ARM11MPCORE) { - int mpidr = env->cpu_index; - /* We don't support setting cluster ID ([8..11]) - * so these bits always RAZ. - */ - if (arm_feature(env, ARM_FEATURE_V7MP)) { - mpidr |= (1 << 31); - /* Cores which are uniprocessor (non-coherent) - * but still implement the MP extensions set - * bit 30. (For instance, A9UP.) However we do - * not currently model any of those cores. - */ - } - return mpidr; - } - /* otherwise fall through to the unimplemented-reg case */ default: goto bad_reg; } -- cgit v1.2.3 From 7884849cc5b99f5e40217765d62809789ef76bc8 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jun 2012 11:57:20 +0000 Subject: target-arm: Convert final ID registers Convert the final ID registers to the new cp15 scheme. Signed-off-by: Peter Maydell --- target-arm/cpu.c | 2 - target-arm/helper.c | 116 ++++++++++++++++++++++++++++++---------------------- 2 files changed, 68 insertions(+), 50 deletions(-) diff --git a/target-arm/cpu.c b/target-arm/cpu.c index 0c031ba88b..3ea352713b 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -72,11 +72,9 @@ static void arm_cpu_reset(CPUState *s) memset(env, 0, offsetof(CPUARMState, breakpoints)); g_hash_table_foreach(cpu->cp_regs, cp_reg_reset, cpu); - env->cp15.c0_cpuid = cpu->midr; env->vfp.xregs[ARM_VFP_FPSID] = cpu->reset_fpsid; env->vfp.xregs[ARM_VFP_MVFR0] = cpu->mvfr0; env->vfp.xregs[ARM_VFP_MVFR1] = cpu->mvfr1; - env->cp15.c0_cachetype = cpu->ctr; if (arm_feature(env, ARM_FEATURE_IWMMXT)) { env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q'; diff --git a/target-arm/helper.c b/target-arm/helper.c index 1acc2128f0..9b28f6b597 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -1003,6 +1003,74 @@ void register_cp_regs_for_features(ARMCPU *cpu) if (arm_feature(env, ARM_FEATURE_MPIDR)) { define_arm_cp_regs(cpu, mpidr_cp_reginfo); } + /* Slightly awkwardly, the OMAP and StrongARM cores need all of + * cp15 crn=0 to be writes-ignored, whereas for other cores they should + * be read-only (ie write causes UNDEF exception). + */ + { + ARMCPRegInfo id_cp_reginfo[] = { + /* Note that the MIDR isn't a simple constant register because + * of the TI925 behaviour where writes to another register can + * cause the MIDR value to change. + */ + { .name = "MIDR", + .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 0, + .access = PL1_R, .resetvalue = cpu->midr, + .writefn = arm_cp_write_ignore, + .fieldoffset = offsetof(CPUARMState, cp15.c0_cpuid) }, + { .name = "CTR", + .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 1, + .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = cpu->ctr }, + { .name = "TCMTR", + .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 2, + .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "TLBTR", + .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 3, + .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 }, + /* crn = 0 op1 = 0 crm = 3..7 : currently unassigned; we RAZ. */ + { .name = "DUMMY", + .cp = 15, .crn = 0, .crm = 3, .opc1 = 0, .opc2 = CP_ANY, + .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "DUMMY", + .cp = 15, .crn = 0, .crm = 4, .opc1 = 0, .opc2 = CP_ANY, + .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "DUMMY", + .cp = 15, .crn = 0, .crm = 5, .opc1 = 0, .opc2 = CP_ANY, + .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "DUMMY", + .cp = 15, .crn = 0, .crm = 6, .opc1 = 0, .opc2 = CP_ANY, + .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "DUMMY", + .cp = 15, .crn = 0, .crm = 7, .opc1 = 0, .opc2 = CP_ANY, + .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 }, + REGINFO_SENTINEL + }; + ARMCPRegInfo crn0_wi_reginfo = { + .name = "CRN0_WI", .cp = 15, .crn = 0, .crm = CP_ANY, + .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_W, + .type = ARM_CP_NOP | ARM_CP_OVERRIDE + }; + if (arm_feature(env, ARM_FEATURE_OMAPCP) || + arm_feature(env, ARM_FEATURE_STRONGARM)) { + ARMCPRegInfo *r; + /* Register the blanket "writes ignored" value first to cover the + * whole space. Then define the specific ID registers, but update + * their access field to allow write access, so that they ignore + * writes rather than causing them to UNDEF. + */ + define_one_arm_cp_reg(cpu, &crn0_wi_reginfo); + for (r = id_cp_reginfo; r->type != ARM_CP_SENTINEL; r++) { + r->access = PL1_RW; + define_one_arm_cp_reg(cpu, r); + } + } else { + /* Just register the standard ID registers (read-only, meaning + * that writes will UNDEF). + */ + define_arm_cp_regs(cpu, id_cp_reginfo); + } + } + if (arm_feature(env, ARM_FEATURE_AUXCR)) { ARMCPRegInfo auxcr = { .name = "AUXCR", .cp = 15, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 1, @@ -2105,21 +2173,6 @@ void HELPER(set_cp15)(CPUARMState *env, uint32_t insn, uint32_t val) op1 = (insn >> 21) & 7; op2 = (insn >> 5) & 7; crm = insn & 0xf; - switch ((insn >> 16) & 0xf) { - case 0: - /* ID codes. */ - if (arm_feature(env, ARM_FEATURE_XSCALE)) - break; - if (arm_feature(env, ARM_FEATURE_OMAPCP)) - break; - goto bad_reg; - case 4: /* Reserved. */ - goto bad_reg; - case 12: /* Reserved. */ - goto bad_reg; - } - return; -bad_reg: /* ??? For debugging only. Should raise illegal instruction exception. */ cpu_abort(env, "Unimplemented cp15 register write (c%d, c%d, {%d, %d})\n", (insn >> 16) & 0xf, crm, op1, op2); @@ -2134,39 +2187,6 @@ uint32_t HELPER(get_cp15)(CPUARMState *env, uint32_t insn) op1 = (insn >> 21) & 7; op2 = (insn >> 5) & 7; crm = insn & 0xf; - switch ((insn >> 16) & 0xf) { - case 0: /* ID codes. */ - switch (op1) { - case 0: - switch (crm) { - case 0: - switch (op2) { - case 0: /* Device ID. */ - return env->cp15.c0_cpuid; - case 1: /* Cache Type. */ - return env->cp15.c0_cachetype; - case 2: /* TCM status. */ - return 0; - case 3: /* TLB type register. */ - return 0; /* No lockable TLB entries. */ - default: - goto bad_reg; - } - case 3: case 4: case 5: case 6: case 7: - return 0; - default: - goto bad_reg; - } - default: - goto bad_reg; - } - case 4: /* Reserved. */ - goto bad_reg; - case 11: /* TCM DMA control. */ - case 12: /* Reserved. */ - goto bad_reg; - } -bad_reg: /* ??? For debugging only. Should raise illegal instruction exception. */ cpu_abort(env, "Unimplemented cp15 register read (c%d, c%d, {%d, %d})\n", (insn >> 16) & 0xf, crm, op1, op2); -- cgit v1.2.3 From b22af022b22091f22deead5f0cbea332b6280acb Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jun 2012 11:57:21 +0000 Subject: target-arm: Remove c0_cachetype CPUARMState field Remove the no-longer-used CPUARMState c0_cachetype field. Although this was a constant register we had it in our migration state. Drop this (with resulting version bump) because for ARM currently we prefer cleaner migration code and have not stabilised migration format yet. Signed-off-by: Peter Maydell --- target-arm/cpu.h | 3 +-- target-arm/machine.c | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 2630fe7739..27e398ba14 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -107,7 +107,6 @@ typedef struct CPUARMState { /* System control coprocessor (cp15) */ struct { uint32_t c0_cpuid; - uint32_t c0_cachetype; uint32_t c0_cssel; /* Cache size selection. */ uint32_t c1_sys; /* System control register. */ uint32_t c1_coproc; /* Coprocessor access register. */ @@ -664,7 +663,7 @@ static inline CPUARMState *cpu_init(const char *cpu_model) #define cpu_signal_handler cpu_arm_signal_handler #define cpu_list arm_cpu_list -#define CPU_SAVE_VERSION 6 +#define CPU_SAVE_VERSION 7 /* MMU modes definitions */ #define MMU_MODE0_SUFFIX _kernel diff --git a/target-arm/machine.c b/target-arm/machine.c index f66b8dfa1f..a2a75fbd19 100644 --- a/target-arm/machine.c +++ b/target-arm/machine.c @@ -21,7 +21,6 @@ void cpu_save(QEMUFile *f, void *opaque) qemu_put_be32(f, env->fiq_regs[i]); } qemu_put_be32(f, env->cp15.c0_cpuid); - qemu_put_be32(f, env->cp15.c0_cachetype); qemu_put_be32(f, env->cp15.c0_cssel); qemu_put_be32(f, env->cp15.c1_sys); qemu_put_be32(f, env->cp15.c1_coproc); @@ -139,7 +138,6 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) env->fiq_regs[i] = qemu_get_be32(f); } env->cp15.c0_cpuid = qemu_get_be32(f); - env->cp15.c0_cachetype = qemu_get_be32(f); env->cp15.c0_cssel = qemu_get_be32(f); env->cp15.c1_sys = qemu_get_be32(f); env->cp15.c1_coproc = qemu_get_be32(f); -- cgit v1.2.3 From 30b05bba1122c13206d85d3704e86ff30cc09750 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jun 2012 11:57:22 +0000 Subject: target-arm: Move block cache ops to new cp15 framework Move the v6 optional block cache ops to the new cp15 framework. This includes only providing them on the CPUs which implemented them, rather than the previous blunderbuss approach of making all MCRR instructions on all CPUs act as NOPs. Signed-off-by: Peter Maydell --- target-arm/helper.c | 13 +++++++++++++ target-arm/translate.c | 7 +------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 9b28f6b597..10d46356e5 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -810,6 +810,19 @@ static const ARMCPRegInfo cache_block_ops_cp_reginfo[] = { /* We never have a a block transfer operation in progress */ { .name = "BXSR", .cp = 15, .crn = 7, .crm = 12, .opc1 = 0, .opc2 = 4, .access = PL0_R, .type = ARM_CP_CONST, .resetvalue = 0 }, + /* The cache ops themselves: these all NOP for QEMU */ + { .name = "IICR", .cp = 15, .crm = 5, .opc1 = 0, + .access = PL1_W, .type = ARM_CP_NOP|ARM_CP_64BIT }, + { .name = "IDCR", .cp = 15, .crm = 6, .opc1 = 0, + .access = PL1_W, .type = ARM_CP_NOP|ARM_CP_64BIT }, + { .name = "CDCR", .cp = 15, .crm = 12, .opc1 = 0, + .access = PL0_W, .type = ARM_CP_NOP|ARM_CP_64BIT }, + { .name = "PIR", .cp = 15, .crm = 12, .opc1 = 1, + .access = PL0_W, .type = ARM_CP_NOP|ARM_CP_64BIT }, + { .name = "PDR", .cp = 15, .crm = 12, .opc1 = 2, + .access = PL0_W, .type = ARM_CP_NOP|ARM_CP_64BIT }, + { .name = "CIDCR", .cp = 15, .crm = 14, .opc1 = 0, + .access = PL1_W, .type = ARM_CP_NOP|ARM_CP_64BIT }, REGINFO_SENTINEL }; diff --git a/target-arm/translate.c b/target-arm/translate.c index f4e9435c4b..fcdc9d3166 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -2451,12 +2451,7 @@ static int disas_cp15_insn(CPUARMState *env, DisasContext *s, uint32_t insn) return 1; if ((insn & (1 << 25)) == 0) { - if (insn & (1 << 20)) { - /* mrrc */ - return 1; - } - /* mcrr. Used for block cache operations, so implement as no-op. */ - return 0; + return 1; } if ((insn & (1 << 4)) == 0) { /* cdp */ -- cgit v1.2.3 From 4a9a539ffb5226009a1bb4aa3a569fcd80cf1436 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jun 2012 11:57:22 +0000 Subject: target-arm: Remove remaining old cp15 infrastructure There are now no uses of the old cp15 infrastructure, so it can be deleted. Signed-off-by: Peter Maydell --- target-arm/helper.c | 39 --------------------------------- target-arm/helper.h | 3 --- target-arm/translate.c | 59 +------------------------------------------------- 3 files changed, 1 insertion(+), 100 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 10d46356e5..23099236ad 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -1441,16 +1441,6 @@ int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address, int rw, return 1; } -void HELPER(set_cp15)(CPUARMState *env, uint32_t insn, uint32_t val) -{ - cpu_abort(env, "cp15 insn %08x\n", insn); -} - -uint32_t HELPER(get_cp15)(CPUARMState *env, uint32_t insn) -{ - cpu_abort(env, "cp15 insn %08x\n", insn); -} - /* These should probably raise undefined insn exceptions. */ void HELPER(v7m_msr)(CPUARMState *env, uint32_t reg, uint32_t val) { @@ -2177,35 +2167,6 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUARMState *env, target_ulong addr) return phys_addr; } -void HELPER(set_cp15)(CPUARMState *env, uint32_t insn, uint32_t val) -{ - int op1; - int op2; - int crm; - - op1 = (insn >> 21) & 7; - op2 = (insn >> 5) & 7; - crm = insn & 0xf; - /* ??? For debugging only. Should raise illegal instruction exception. */ - cpu_abort(env, "Unimplemented cp15 register write (c%d, c%d, {%d, %d})\n", - (insn >> 16) & 0xf, crm, op1, op2); -} - -uint32_t HELPER(get_cp15)(CPUARMState *env, uint32_t insn) -{ - int op1; - int op2; - int crm; - - op1 = (insn >> 21) & 7; - op2 = (insn >> 5) & 7; - crm = insn & 0xf; - /* ??? For debugging only. Should raise illegal instruction exception. */ - cpu_abort(env, "Unimplemented cp15 register read (c%d, c%d, {%d, %d})\n", - (insn >> 16) & 0xf, crm, op1, op2); - return 0; -} - void HELPER(set_r13_banked)(CPUARMState *env, uint32_t mode, uint32_t val) { if ((env->uncached_cpsr & CPSR_M) == mode) { diff --git a/target-arm/helper.h b/target-arm/helper.h index a0034ae630..21e9cfe05f 100644 --- a/target-arm/helper.h +++ b/target-arm/helper.h @@ -59,9 +59,6 @@ DEF_HELPER_0(cpsr_read, i32) DEF_HELPER_3(v7m_msr, void, env, i32, i32) DEF_HELPER_2(v7m_mrs, i32, env, i32) -DEF_HELPER_3(set_cp15, void, env, i32, i32) -DEF_HELPER_2(get_cp15, i32, env, i32) - DEF_HELPER_3(set_cp_reg, void, env, ptr, i32) DEF_HELPER_2(get_cp_reg, i32, env, ptr) DEF_HELPER_3(set_cp_reg64, void, env, ptr, i64) diff --git a/target-arm/translate.c b/target-arm/translate.c index fcdc9d3166..a2a0ecddad 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -2439,55 +2439,6 @@ static int disas_dsp_insn(CPUARMState *env, DisasContext *s, uint32_t insn) return 1; } -/* Disassemble system coprocessor (cp15) instruction. Return nonzero if - instruction is not defined. */ -static int disas_cp15_insn(CPUARMState *env, DisasContext *s, uint32_t insn) -{ - uint32_t rd; - TCGv tmp, tmp2; - - /* M profile cores use memory mapped registers instead of cp15. */ - if (arm_feature(env, ARM_FEATURE_M)) - return 1; - - if ((insn & (1 << 25)) == 0) { - return 1; - } - if ((insn & (1 << 4)) == 0) { - /* cdp */ - return 1; - } - - if (IS_USER(s)) { - return 1; - } - - rd = (insn >> 12) & 0xf; - - tmp2 = tcg_const_i32(insn); - if (insn & ARM_CP_RW_BIT) { - tmp = tcg_temp_new_i32(); - gen_helper_get_cp15(tmp, cpu_env, tmp2); - /* If the destination register is r15 then sets condition codes. */ - if (rd != 15) - store_reg(s, rd, tmp); - else - tcg_temp_free_i32(tmp); - } else { - tmp = load_reg(s, rd); - gen_helper_set_cp15(cpu_env, tmp2, tmp); - tcg_temp_free_i32(tmp); - /* Normally we would always end the TB here, but Linux - * arch/arm/mach-pxa/sleep.S expects two instructions following - * an MMU enable to execute from cache. Imitate this behaviour. */ - if (!arm_feature(env, ARM_FEATURE_XSCALE) || - (insn & 0x0fff0fff) != 0x0e010f10) - gen_lookup_tb(s); - } - tcg_temp_free_i32(tmp2); - return 0; -} - #define VFP_REG_SHR(x, n) (((n) > 0) ? (x) >> (n) : (x) << -(n)) #define VFP_SREG(insn, bigbit, smallbit) \ ((VFP_REG_SHR(insn, bigbit - 1) & 0x1e) | (((insn) >> (smallbit)) & 1)) @@ -6388,15 +6339,7 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn) return 0; } - /* Fallback code: handle coprocessor registers not yet converted - * to ARMCPRegInfo. - */ - switch (cpnum) { - case 15: - return disas_cp15_insn (env, s, insn); - default: - return 1; - } + return 1; } -- cgit v1.2.3 From b2d06f9607e36333686b0e52a188881ce38495c7 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Jun 2012 11:57:23 +0000 Subject: target-arm: Remove ARM_CPUID_* macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All the uses of ARM_CPUID() to vary behaviour have now been removed, so we can delete the ARM_CPUID_* macros now. The one exception is the TI915T/925T, because of its odd behaviour where the MIDR value can be changed at runtime. Signed-off-by: Peter Maydell Reviewed-by: Andreas Färber --- linux-user/cpu-uname.c | 5 +---- target-arm/cpu.c | 50 +++++++++++++++++++++++++------------------------- target-arm/cpu.h | 27 --------------------------- 3 files changed, 26 insertions(+), 56 deletions(-) diff --git a/linux-user/cpu-uname.c b/linux-user/cpu-uname.c index ddc37be4f9..59cd6477d5 100644 --- a/linux-user/cpu-uname.c +++ b/linux-user/cpu-uname.c @@ -35,10 +35,7 @@ const char *cpu_to_uname_machine(void *cpu_env) * armv7l; to get a list of CPU arch names from the linux source, use: * grep arch_name: -A1 linux/arch/arm/mm/proc-*.S * see arch/arm/kernel/setup.c: setup_processor() - * - * to test by CPU id, compare cpu_env->cp15.c0_cpuid to ARM_CPUID_* - * defines and to test by CPU feature, use arm_feature(cpu_env, - * ARM_FEATURE_*) */ + */ /* in theory, endianness is configurable on some ARM CPUs, but this isn't * used in user mode emulation */ diff --git a/target-arm/cpu.c b/target-arm/cpu.c index 3ea352713b..ae5795337f 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -205,7 +205,7 @@ static void arm926_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_VFP); set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); set_feature(&cpu->env, ARM_FEATURE_CACHE_TEST_CLEAN); - cpu->midr = ARM_CPUID_ARM926; + cpu->midr = 0x41069265; cpu->reset_fpsid = 0x41011090; cpu->ctr = 0x1dd20d2; cpu->reset_sctlr = 0x00090078; @@ -217,7 +217,7 @@ static void arm946_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_V5); set_feature(&cpu->env, ARM_FEATURE_MPU); set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); - cpu->midr = ARM_CPUID_ARM946; + cpu->midr = 0x41059461; cpu->ctr = 0x0f004006; cpu->reset_sctlr = 0x00000078; } @@ -230,7 +230,7 @@ static void arm1026_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_AUXCR); set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); set_feature(&cpu->env, ARM_FEATURE_CACHE_TEST_CLEAN); - cpu->midr = ARM_CPUID_ARM1026; + cpu->midr = 0x4106a262; cpu->reset_fpsid = 0x410110a0; cpu->ctr = 0x1dd20d2; cpu->reset_sctlr = 0x00090078; @@ -262,7 +262,7 @@ static void arm1136_r2_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG); set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS); - cpu->midr = ARM_CPUID_ARM1136_R2; + cpu->midr = 0x4107b362; cpu->reset_fpsid = 0x410120b4; cpu->mvfr0 = 0x11111111; cpu->mvfr1 = 0x00000000; @@ -292,7 +292,7 @@ static void arm1136_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG); set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS); - cpu->midr = ARM_CPUID_ARM1136; + cpu->midr = 0x4117b363; cpu->reset_fpsid = 0x410120b4; cpu->mvfr0 = 0x11111111; cpu->mvfr1 = 0x00000000; @@ -322,7 +322,7 @@ static void arm1176_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG); set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS); - cpu->midr = ARM_CPUID_ARM1176; + cpu->midr = 0x410fb767; cpu->reset_fpsid = 0x410120b5; cpu->mvfr0 = 0x11111111; cpu->mvfr1 = 0x00000000; @@ -351,7 +351,7 @@ static void arm11mpcore_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_VAPA); set_feature(&cpu->env, ARM_FEATURE_MPIDR); set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); - cpu->midr = ARM_CPUID_ARM11MPCORE; + cpu->midr = 0x410fb022; cpu->reset_fpsid = 0x410120b4; cpu->mvfr0 = 0x11111111; cpu->mvfr1 = 0x00000000; @@ -376,7 +376,7 @@ static void cortex_m3_initfn(Object *obj) ARMCPU *cpu = ARM_CPU(obj); set_feature(&cpu->env, ARM_FEATURE_V7); set_feature(&cpu->env, ARM_FEATURE_M); - cpu->midr = ARM_CPUID_CORTEXM3; + cpu->midr = 0x410fc231; } static const ARMCPRegInfo cortexa8_cp_reginfo[] = { @@ -395,7 +395,7 @@ static void cortex_a8_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_NEON); set_feature(&cpu->env, ARM_FEATURE_THUMB2EE); set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); - cpu->midr = ARM_CPUID_CORTEXA8; + cpu->midr = 0x410fc080; cpu->reset_fpsid = 0x410330c0; cpu->mvfr0 = 0x11110222; cpu->mvfr1 = 0x00011100; @@ -464,7 +464,7 @@ static void cortex_a9_initfn(Object *obj) * and valid configurations; we don't model A9UP). */ set_feature(&cpu->env, ARM_FEATURE_V7MP); - cpu->midr = ARM_CPUID_CORTEXA9; + cpu->midr = 0x410fc090; cpu->reset_fpsid = 0x41033090; cpu->mvfr0 = 0x11110222; cpu->mvfr1 = 0x01111111; @@ -532,7 +532,7 @@ static void cortex_a15_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_V7MP); set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); - cpu->midr = ARM_CPUID_CORTEXA15; + cpu->midr = 0x412fc0f1; cpu->reset_fpsid = 0x410430f0; cpu->mvfr0 = 0x10110222; cpu->mvfr1 = 0x11111111; @@ -573,7 +573,7 @@ static void sa1100_initfn(Object *obj) ARMCPU *cpu = ARM_CPU(obj); set_feature(&cpu->env, ARM_FEATURE_STRONGARM); set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); - cpu->midr = ARM_CPUID_SA1100; + cpu->midr = 0x4401A11B; cpu->reset_sctlr = 0x00000070; } @@ -582,7 +582,7 @@ static void sa1110_initfn(Object *obj) ARMCPU *cpu = ARM_CPU(obj); set_feature(&cpu->env, ARM_FEATURE_STRONGARM); set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); - cpu->midr = ARM_CPUID_SA1110; + cpu->midr = 0x6901B119; cpu->reset_sctlr = 0x00000070; } @@ -591,7 +591,7 @@ static void pxa250_initfn(Object *obj) ARMCPU *cpu = ARM_CPU(obj); set_feature(&cpu->env, ARM_FEATURE_V5); set_feature(&cpu->env, ARM_FEATURE_XSCALE); - cpu->midr = ARM_CPUID_PXA250; + cpu->midr = 0x69052100; cpu->ctr = 0xd172172; cpu->reset_sctlr = 0x00000078; } @@ -601,7 +601,7 @@ static void pxa255_initfn(Object *obj) ARMCPU *cpu = ARM_CPU(obj); set_feature(&cpu->env, ARM_FEATURE_V5); set_feature(&cpu->env, ARM_FEATURE_XSCALE); - cpu->midr = ARM_CPUID_PXA255; + cpu->midr = 0x69052d00; cpu->ctr = 0xd172172; cpu->reset_sctlr = 0x00000078; } @@ -611,7 +611,7 @@ static void pxa260_initfn(Object *obj) ARMCPU *cpu = ARM_CPU(obj); set_feature(&cpu->env, ARM_FEATURE_V5); set_feature(&cpu->env, ARM_FEATURE_XSCALE); - cpu->midr = ARM_CPUID_PXA260; + cpu->midr = 0x69052903; cpu->ctr = 0xd172172; cpu->reset_sctlr = 0x00000078; } @@ -621,7 +621,7 @@ static void pxa261_initfn(Object *obj) ARMCPU *cpu = ARM_CPU(obj); set_feature(&cpu->env, ARM_FEATURE_V5); set_feature(&cpu->env, ARM_FEATURE_XSCALE); - cpu->midr = ARM_CPUID_PXA261; + cpu->midr = 0x69052d05; cpu->ctr = 0xd172172; cpu->reset_sctlr = 0x00000078; } @@ -631,7 +631,7 @@ static void pxa262_initfn(Object *obj) ARMCPU *cpu = ARM_CPU(obj); set_feature(&cpu->env, ARM_FEATURE_V5); set_feature(&cpu->env, ARM_FEATURE_XSCALE); - cpu->midr = ARM_CPUID_PXA262; + cpu->midr = 0x69052d06; cpu->ctr = 0xd172172; cpu->reset_sctlr = 0x00000078; } @@ -642,7 +642,7 @@ static void pxa270a0_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_V5); set_feature(&cpu->env, ARM_FEATURE_XSCALE); set_feature(&cpu->env, ARM_FEATURE_IWMMXT); - cpu->midr = ARM_CPUID_PXA270_A0; + cpu->midr = 0x69054110; cpu->ctr = 0xd172172; cpu->reset_sctlr = 0x00000078; } @@ -653,7 +653,7 @@ static void pxa270a1_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_V5); set_feature(&cpu->env, ARM_FEATURE_XSCALE); set_feature(&cpu->env, ARM_FEATURE_IWMMXT); - cpu->midr = ARM_CPUID_PXA270_A1; + cpu->midr = 0x69054111; cpu->ctr = 0xd172172; cpu->reset_sctlr = 0x00000078; } @@ -664,7 +664,7 @@ static void pxa270b0_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_V5); set_feature(&cpu->env, ARM_FEATURE_XSCALE); set_feature(&cpu->env, ARM_FEATURE_IWMMXT); - cpu->midr = ARM_CPUID_PXA270_B0; + cpu->midr = 0x69054112; cpu->ctr = 0xd172172; cpu->reset_sctlr = 0x00000078; } @@ -675,7 +675,7 @@ static void pxa270b1_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_V5); set_feature(&cpu->env, ARM_FEATURE_XSCALE); set_feature(&cpu->env, ARM_FEATURE_IWMMXT); - cpu->midr = ARM_CPUID_PXA270_B1; + cpu->midr = 0x69054113; cpu->ctr = 0xd172172; cpu->reset_sctlr = 0x00000078; } @@ -686,7 +686,7 @@ static void pxa270c0_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_V5); set_feature(&cpu->env, ARM_FEATURE_XSCALE); set_feature(&cpu->env, ARM_FEATURE_IWMMXT); - cpu->midr = ARM_CPUID_PXA270_C0; + cpu->midr = 0x69054114; cpu->ctr = 0xd172172; cpu->reset_sctlr = 0x00000078; } @@ -697,7 +697,7 @@ static void pxa270c5_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_V5); set_feature(&cpu->env, ARM_FEATURE_XSCALE); set_feature(&cpu->env, ARM_FEATURE_IWMMXT); - cpu->midr = ARM_CPUID_PXA270_C5; + cpu->midr = 0x69054117; cpu->ctr = 0xd172172; cpu->reset_sctlr = 0x00000078; } @@ -712,7 +712,7 @@ static void arm_any_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_THUMB2EE); set_feature(&cpu->env, ARM_FEATURE_ARM_DIV); set_feature(&cpu->env, ARM_FEATURE_V7MP); - cpu->midr = ARM_CPUID_ANY; + cpu->midr = 0xffffffff; } typedef struct ARMCPUInfo { diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 27e398ba14..33afa185e9 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -606,36 +606,9 @@ static inline bool cp_access_ok(CPUARMState *env, conventional cores (ie. Application or Realtime profile). */ #define IS_M(env) arm_feature(env, ARM_FEATURE_M) -#define ARM_CPUID(env) (env->cp15.c0_cpuid) -#define ARM_CPUID_ARM1026 0x4106a262 -#define ARM_CPUID_ARM926 0x41069265 -#define ARM_CPUID_ARM946 0x41059461 #define ARM_CPUID_TI915T 0x54029152 #define ARM_CPUID_TI925T 0x54029252 -#define ARM_CPUID_SA1100 0x4401A11B -#define ARM_CPUID_SA1110 0x6901B119 -#define ARM_CPUID_PXA250 0x69052100 -#define ARM_CPUID_PXA255 0x69052d00 -#define ARM_CPUID_PXA260 0x69052903 -#define ARM_CPUID_PXA261 0x69052d05 -#define ARM_CPUID_PXA262 0x69052d06 -#define ARM_CPUID_PXA270 0x69054110 -#define ARM_CPUID_PXA270_A0 0x69054110 -#define ARM_CPUID_PXA270_A1 0x69054111 -#define ARM_CPUID_PXA270_B0 0x69054112 -#define ARM_CPUID_PXA270_B1 0x69054113 -#define ARM_CPUID_PXA270_C0 0x69054114 -#define ARM_CPUID_PXA270_C5 0x69054117 -#define ARM_CPUID_ARM1136 0x4117b363 -#define ARM_CPUID_ARM1136_R2 0x4107b362 -#define ARM_CPUID_ARM1176 0x410fb767 -#define ARM_CPUID_ARM11MPCORE 0x410fb022 -#define ARM_CPUID_CORTEXA8 0x410fc080 -#define ARM_CPUID_CORTEXA9 0x410fc090 -#define ARM_CPUID_CORTEXA15 0x412fc0f1 -#define ARM_CPUID_CORTEXM3 0x410fc231 -#define ARM_CPUID_ANY 0xffffffff #if defined(CONFIG_USER_ONLY) #define TARGET_PAGE_BITS 12 -- cgit v1.2.3