Re: [Qemu-devel] [PATCH 07/24] target-arm: A64: Make cache ID registers visible to AArch64
On 28 January 2014 01:46, Peter Crosthwaite peter.crosthwa...@xilinx.com wrote: There seem to be multiple instances in this series where you fallback to open coded R/W accessor functions for the sake of access checks. Is it better to define a bool check_access() fn hook in ARMCPRegInfo and leave the actual write/read behaviour to the data driven mechanisms? This may also minimise the need for raw_write hook usages as it serves to isolate the actual state change into its own self contained definition (whether open coded or not). Yes, I think it's probably going to be better to do that. We may need to make it more than just bool, though since for AArch64 the kind of exception can be different I think -- the specific syndrome information can vary. thanks -- PMM
Re: [Qemu-devel] [PATCH 07/24] target-arm: A64: Make cache ID registers visible to AArch64
On Tue, Jan 28, 2014 at 6:45 PM, Peter Maydell peter.mayd...@linaro.org wrote: On 28 January 2014 01:46, Peter Crosthwaite peter.crosthwa...@xilinx.com wrote: There seem to be multiple instances in this series where you fallback to open coded R/W accessor functions for the sake of access checks. Is it better to define a bool check_access() fn hook in ARMCPRegInfo and leave the actual write/read behaviour to the data driven mechanisms? This may also minimise the need for raw_write hook usages as it serves to isolate the actual state change into its own self contained definition (whether open coded or not). Yes, I think it's probably going to be better to do that. We may need to make it more than just bool, though since for AArch64 the kind of exception can be different I think -- the specific syndrome information can vary. I guess then it's simplest to just return in same format as read/write accessors. Regards, Peter thanks -- PMM
Re: [Qemu-devel] [PATCH 07/24] target-arm: A64: Make cache ID registers visible to AArch64
On 28 January 2014 14:05, Peter Crosthwaite peter.crosthwa...@xilinx.com wrote: On Tue, Jan 28, 2014 at 6:45 PM, Peter Maydell peter.mayd...@linaro.org wrote: On 28 January 2014 01:46, Peter Crosthwaite peter.crosthwa...@xilinx.com wrote: There seem to be multiple instances in this series where you fallback to open coded R/W accessor functions for the sake of access checks. Is it better to define a bool check_access() fn hook in ARMCPRegInfo and leave the actual write/read behaviour to the data driven mechanisms? This may also minimise the need for raw_write hook usages as it serves to isolate the actual state change into its own self contained definition (whether open coded or not). Yes, I think it's probably going to be better to do that. We may need to make it more than just bool, though since for AArch64 the kind of exception can be different I think -- the specific syndrome information can vary. I guess then it's simplest to just return in same format as read/write accessors. Well, AArch64 means we also can't just return EXCP_UDEF or 0, but ideally return at least some syndrome information. I haven't quite figured out the nicest way to do this yet. My current work in progress has: * retain all the AArch32 EXCP_* classes as values for env-exception_index * whenever we generate an exception, also set up syndrome register information in the cpu state struct; the syndrome register high 6 bits happen to contain a category code, but we don't map this to an env-exception_index So for AArch64, access functions need to be able to return one of three things: (1) no exception, ie access OK (2) exception which in UNDEF if taken to AArch32, or a synchronous exception with ESR_ELx.EC = 0 (uncategorized) if taken to AArch64 (3) exception which is UNDEF if taken to AArch32, or a synchronous exception with ESR_ELx.EC == 0x3/4/5/6/C/18 if taken to AArch64 (exact category depends on the insn used to access the register, and ESR_ELx includes all the opc1/2/crn/crm fields from the insn) -- this generally is used for access failed because of a configurable trap or enable bit so we need to at least return a three-way ok/disabled/undef code. I think actually most if not all of our current access checks done in read/write fns should be type (2), but I don't want to leave us stuck if we find one that needs to be type (1) now or in the future. Failures due to the ri-access permissions are always type (1). We could return a complete EXCP_* value plus syndrome, but that seems like overkill especially since the calling code has most of the info needed for putting the syndrome together properly. So I think: typedef enum CPAccessResult { /* Access is permitted */ CP_ACCESS_OK = 0, /* Access fails due to a configurable trap or enable which would * result in an exception syndrome other than 'uncategorized' */ CP_ACCESS_TRAP = 1, /* Access fails and should result in an exception syndrome of * 'uncategorized' */ CP_ACCESS_TRAP = 2, } CPAccessResult; typedef CPAccessResult CPAccessFn(CPUARMState *env, const ARMCPRegInfo *opaque); and an entry in ARMCPRegInfo: /* Function for checking access permissions for the register * which should be done in addition to those specified by * the access field. If NULL, no extra checks required. */ CPAccessFn accessfn; and CPReadFn and CPWriteFn both go from 'int' return to 'void' return. (Anybody got a better name than CPAccessResult for the enum type?) thanks -- PMM
Re: [Qemu-devel] [PATCH 07/24] target-arm: A64: Make cache ID registers visible to AArch64
On 28 January 2014 18:12, Peter Maydell peter.mayd...@linaro.org wrote: typedef enum CPAccessResult { /* Access is permitted */ CP_ACCESS_OK = 0, /* Access fails due to a configurable trap or enable which would * result in an exception syndrome other than 'uncategorized' */ CP_ACCESS_TRAP = 1, /* Access fails and should result in an exception syndrome of * 'uncategorized' */ CP_ACCESS_TRAP = 2, } CPAccessResult; The =2 case should be some other name, of course. I'd rather not use the obvious CP_ACCESS_UNCATEGORIZED because that implies use this if you don't know, when actually the set of things which cause Uncategorized exceptions is a specific list, and it's the 'due to a configurable trap' case which is defined as all those which aren't defined to cause an Uncategorized exception. On the other hand I can't come up with a better name right now... thanks -- PMM
Re: [Qemu-devel] [PATCH 07/24] target-arm: A64: Make cache ID registers visible to AArch64
On Wed, Jan 22, 2014 at 6:12 AM, Peter Maydell peter.mayd...@linaro.org wrote: Make the cache ID system registers (CLIDR, CCSELR, CCSIDR, CTR) visible to AArch64. These are mostly simple 64-bit extensions of the existing 32 bit system registers and so can share reginfo definitions. CTR needs to have a split definition, but we can clean up the temporary user-mode implementation in favour of using the CPU-specified reset value, and implement the system-mode-required semantics of restricting its EL0 accessibility if SCTLR.UCT is not set. Signed-off-by: Peter Maydell peter.mayd...@linaro.org --- target-arm/cpu.c| 2 ++ target-arm/cpu.h| 2 +- target-arm/cpu64.c | 1 + target-arm/helper.c | 33 +++-- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/target-arm/cpu.c b/target-arm/cpu.c index c1e55c8..1e08802 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -91,6 +91,8 @@ static void arm_cpu_reset(CPUState *s) env-aarch64 = 1; #if defined(CONFIG_USER_ONLY) env-pstate = PSTATE_MODE_EL0t; +/* Userspace expects access to CTL_EL0 */ +env-cp15.c1_sys |= SCTLR_UCT; #else env-pstate = PSTATE_D | PSTATE_A | PSTATE_I | PSTATE_F | PSTATE_MODE_EL1h; diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 1aa4495..1966a19 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -166,7 +166,7 @@ typedef struct CPUARMState { /* System control coprocessor (cp15) */ struct { uint32_t c0_cpuid; -uint32_t c0_cssel; /* Cache size selection. */ +uint64_t c0_cssel; /* Cache size selection. */ 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/cpu64.c b/target-arm/cpu64.c index a639c2e..8426bf1 100644 --- a/target-arm/cpu64.c +++ b/target-arm/cpu64.c @@ -45,6 +45,7 @@ static void aarch64_any_initfn(Object *obj) set_feature(cpu-env, ARM_FEATURE_ARM_DIV); set_feature(cpu-env, ARM_FEATURE_V7MP); set_feature(cpu-env, ARM_FEATURE_AARCH64); +cpu-ctr = 0x80030003; /* 32 byte I and D cacheline size, VIPT icache */ } #endif diff --git a/target-arm/helper.c b/target-arm/helper.c index 205e36a..204d7c3 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -676,9 +676,11 @@ 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, +{ .name = CCSIDR, .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 0, .access = PL1_R, .readfn = ccsidr_read, .type = ARM_CP_NO_MIGRATE }, -{ .name = CSSELR, .cp = 15, .crn = 0, .crm = 0, .opc1 = 2, .opc2 = 0, +{ .name = CSSELR, .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .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 @@ -1601,13 +1603,6 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { { .name = FPSR, .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .opc2 = 1, .crn = 4, .crm = 4, .access = PL0_RW, .readfn = aa64_fpsr_read, .writefn = aa64_fpsr_write }, -/* This claims a 32 byte cacheline size for icache and dcache, VIPT icache. - * It will eventually need to have a CPU-specified reset value. - */ -{ .name = CTR_EL0, .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 3, .opc2 = 1, .crn = 0, .crm = 0, - .access = PL0_R, .type = ARM_CP_CONST, - .resetvalue = 0x80030003 }, /* Prohibit use of DC ZVA. OPTME: implement DC ZVA and allow its use. * For system mode the DZP bit here will need to be computed, not constant. */ @@ -1627,6 +1622,20 @@ static int sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) return 0; } +static int ctr_el0_read(CPUARMState *env, const ARMCPRegInfo *ri, +uint64_t *value) +{ +/* This register is constant, but only accessible in AArch64 EL0 if + * SCTLR.UCT is set. + */ +ARMCPU *cpu = arm_env_get_cpu(env); +if (arm_current_pl(env) == 0 !(env-cp15.c1_sys SCTLR_UCT)) { +return EXCP_UDEF; +} There seem to be multiple instances in this series where you fallback to open coded R/W accessor functions for the sake of access checks. Is it better to define a bool check_access() fn hook in ARMCPRegInfo and leave the actual write/read behaviour to the data driven mechanisms? This may also minimise the need for raw_write
[Qemu-devel] [PATCH 07/24] target-arm: A64: Make cache ID registers visible to AArch64
Make the cache ID system registers (CLIDR, CCSELR, CCSIDR, CTR) visible to AArch64. These are mostly simple 64-bit extensions of the existing 32 bit system registers and so can share reginfo definitions. CTR needs to have a split definition, but we can clean up the temporary user-mode implementation in favour of using the CPU-specified reset value, and implement the system-mode-required semantics of restricting its EL0 accessibility if SCTLR.UCT is not set. Signed-off-by: Peter Maydell peter.mayd...@linaro.org --- target-arm/cpu.c| 2 ++ target-arm/cpu.h| 2 +- target-arm/cpu64.c | 1 + target-arm/helper.c | 33 +++-- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/target-arm/cpu.c b/target-arm/cpu.c index c1e55c8..1e08802 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -91,6 +91,8 @@ static void arm_cpu_reset(CPUState *s) env-aarch64 = 1; #if defined(CONFIG_USER_ONLY) env-pstate = PSTATE_MODE_EL0t; +/* Userspace expects access to CTL_EL0 */ +env-cp15.c1_sys |= SCTLR_UCT; #else env-pstate = PSTATE_D | PSTATE_A | PSTATE_I | PSTATE_F | PSTATE_MODE_EL1h; diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 1aa4495..1966a19 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -166,7 +166,7 @@ typedef struct CPUARMState { /* System control coprocessor (cp15) */ struct { uint32_t c0_cpuid; -uint32_t c0_cssel; /* Cache size selection. */ +uint64_t c0_cssel; /* Cache size selection. */ 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/cpu64.c b/target-arm/cpu64.c index a639c2e..8426bf1 100644 --- a/target-arm/cpu64.c +++ b/target-arm/cpu64.c @@ -45,6 +45,7 @@ static void aarch64_any_initfn(Object *obj) set_feature(cpu-env, ARM_FEATURE_ARM_DIV); set_feature(cpu-env, ARM_FEATURE_V7MP); set_feature(cpu-env, ARM_FEATURE_AARCH64); +cpu-ctr = 0x80030003; /* 32 byte I and D cacheline size, VIPT icache */ } #endif diff --git a/target-arm/helper.c b/target-arm/helper.c index 205e36a..204d7c3 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -676,9 +676,11 @@ 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, +{ .name = CCSIDR, .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 0, .access = PL1_R, .readfn = ccsidr_read, .type = ARM_CP_NO_MIGRATE }, -{ .name = CSSELR, .cp = 15, .crn = 0, .crm = 0, .opc1 = 2, .opc2 = 0, +{ .name = CSSELR, .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .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 @@ -1601,13 +1603,6 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { { .name = FPSR, .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .opc2 = 1, .crn = 4, .crm = 4, .access = PL0_RW, .readfn = aa64_fpsr_read, .writefn = aa64_fpsr_write }, -/* This claims a 32 byte cacheline size for icache and dcache, VIPT icache. - * It will eventually need to have a CPU-specified reset value. - */ -{ .name = CTR_EL0, .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 3, .opc2 = 1, .crn = 0, .crm = 0, - .access = PL0_R, .type = ARM_CP_CONST, - .resetvalue = 0x80030003 }, /* Prohibit use of DC ZVA. OPTME: implement DC ZVA and allow its use. * For system mode the DZP bit here will need to be computed, not constant. */ @@ -1627,6 +1622,20 @@ static int sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) return 0; } +static int ctr_el0_read(CPUARMState *env, const ARMCPRegInfo *ri, +uint64_t *value) +{ +/* This register is constant, but only accessible in AArch64 EL0 if + * SCTLR.UCT is set. + */ +ARMCPU *cpu = arm_env_get_cpu(env); +if (arm_current_pl(env) == 0 !(env-cp15.c1_sys SCTLR_UCT)) { +return EXCP_UDEF; +} +*value = cpu-ctr; +return 0; +} + void register_cp_regs_for_features(ARMCPU *cpu) { /* Register all the coprocessor registers based on feature bits */ @@ -1711,7 +1720,8 @@ void register_cp_regs_for_features(ARMCPU *cpu) .raw_readfn = raw_read, .raw_writefn = raw_write, }; ARMCPRegInfo clidr = { -.name = CLIDR, .cp = 15, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 1, +.name = CLIDR, .state = ARM_CP_STATE_BOTH, +.opc0 = 3,