mirror of https://gitee.com/openkylin/qemu.git
target-arm queue:
* Fix a bug causing an assertion in the NVIC on ARMv7M models * More A64 Neon instructions * Refactor cpreg API to separate out access check functions, as groundwork for AArch64 system mode * Fix bug in linux-user A64 store-exclusive of XZR -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABCAAGBQJTBeM5AAoJEDwlJe0UNgzecwwP/1mujaECNj2BPWxGMLTzF4M5 2PCLYbTNPZumb1b6Z1qrCVbrGBS7bKL1lSCKA5Isji1HHyRnNtaJNGMqI7p2AzaE pPvI+0jhrmdbG2cqgeGbbYMabNdzBTEAhwPo5LQO7wP6CYQDlYH3JVVlcYc6Vl7b hahAI49AV1HM+Xo9z7DSI2VSA2rI2tgbHpIHrvYwtp2exQnPNZBMyZu42yJdK2Lb 1gsVvnni/mA71KydbM6drhHzk2wd9OrrkFxZG94kOIWUxzarDxIapWUPWr006j7c wd2jA639OM9wGwyLgmO537smxr+iV7iLAdz6JkI026po3GFxrrmSjVXS93vL9GHP 716kvTKHeG2WRJW1H0uJjUpzw4tFoKv8EQq3rv8McBwe6Cf+nJtfsY5OLa2GpzG5 bro6jeJmogoInfMxGxYPezeWFg0olBa17RgAZk9+Y33vPjQVbgGb9Xna1dndtbrU e2/T6CAGIGXL3kXLFIiFGB1JBST4UGlGVX2kJLJU+Yv8nzdAZjwQ3gZFJno5DyFU K9BZQGX932VCf4bgy1MPvZXO3pMN2iF7prDeHVZeGcw/zFTBDQHje32fCLFAGeuz 1qnIGvE/vXZQoaw52qv/kIGLmcBZiXiBNCm+ImttfGu5fjAhODEuAhBBU1Zjv3j7 1qnBhXlVSxOpLMpuJTIJ =h/1p -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20140220' into staging target-arm queue: * Fix a bug causing an assertion in the NVIC on ARMv7M models * More A64 Neon instructions * Refactor cpreg API to separate out access check functions, as groundwork for AArch64 system mode * Fix bug in linux-user A64 store-exclusive of XZR # gpg: Signature made Thu 20 Feb 2014 11:12:57 GMT using RSA key ID 14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" * remotes/pmaydell/tags/pull-target-arm-20140220: (30 commits) linux-user: AArch64: Fix exclusive store of the zero register target-arm: A64: Implement unprivileged load/store target-arm: A64: Implement narrowing three-reg-diff operations target-arm: A64: Implement the wide 3-reg-different operations target-arm: A64: Add most remaining three-reg-diff widening ops target-arm: A64: Add opcode comments to disas_simd_three_reg_diff target-arm: A64: Implement store-exclusive for system mode target-arm: Fix incorrect type for value argument to write_raw_cp_reg target-arm: Remove failure status return from read/write_raw_cp_reg target-arm: Remove unnecessary code now read/write fns can't fail target-arm: Drop success/fail return from cpreg read and write functions target-arm: Convert miscellaneous reginfo structs to accessfn target-arm: Convert generic timer reginfo to accessfn target-arm: Convert performance monitor reginfo to accessfn target-arm: Split cpreg access checks out from read/write functions target-arm: Stop underdecoding ARM946 PRBS registers target-arm: Log bad system register accesses with LOG_UNIMP target-arm: Remove unused ARMCPUState sr substruct target-arm: Restrict check_ap() use of S and R bits to v6 and earlier target-arm: Define names for SCTLR bits ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
105a060188
|
@ -2372,6 +2372,17 @@ float32 float32_muladd(float32 a, float32 b, float32 c, int flags STATUS_PARAM)
|
|||
}
|
||||
}
|
||||
/* Zero plus something non-zero : just return the something */
|
||||
if (flags & float_muladd_halve_result) {
|
||||
if (cExp == 0) {
|
||||
normalizeFloat32Subnormal(cSig, &cExp, &cSig);
|
||||
}
|
||||
/* Subtract one to halve, and one again because roundAndPackFloat32
|
||||
* wants one less than the true exponent.
|
||||
*/
|
||||
cExp -= 2;
|
||||
cSig = (cSig | 0x00800000) << 7;
|
||||
return roundAndPackFloat32(cSign ^ signflip, cExp, cSig STATUS_VAR);
|
||||
}
|
||||
return packFloat32(cSign ^ signflip, cExp, cSig);
|
||||
}
|
||||
|
||||
|
@ -2408,6 +2419,9 @@ float32 float32_muladd(float32 a, float32 b, float32 c, int flags STATUS_PARAM)
|
|||
/* Throw out the special case of c being an exact zero now */
|
||||
shift64RightJamming(pSig64, 32, &pSig64);
|
||||
pSig = pSig64;
|
||||
if (flags & float_muladd_halve_result) {
|
||||
pExp--;
|
||||
}
|
||||
return roundAndPackFloat32(zSign, pExp - 1,
|
||||
pSig STATUS_VAR);
|
||||
}
|
||||
|
@ -2472,6 +2486,10 @@ float32 float32_muladd(float32 a, float32 b, float32 c, int flags STATUS_PARAM)
|
|||
zSig64 <<= shiftcount;
|
||||
zExp -= shiftcount;
|
||||
}
|
||||
if (flags & float_muladd_halve_result) {
|
||||
zExp--;
|
||||
}
|
||||
|
||||
shift64RightJamming(zSig64, 32, &zSig64);
|
||||
return roundAndPackFloat32(zSign, zExp, zSig64 STATUS_VAR);
|
||||
}
|
||||
|
@ -4088,6 +4106,17 @@ float64 float64_muladd(float64 a, float64 b, float64 c, int flags STATUS_PARAM)
|
|||
}
|
||||
}
|
||||
/* Zero plus something non-zero : just return the something */
|
||||
if (flags & float_muladd_halve_result) {
|
||||
if (cExp == 0) {
|
||||
normalizeFloat64Subnormal(cSig, &cExp, &cSig);
|
||||
}
|
||||
/* Subtract one to halve, and one again because roundAndPackFloat64
|
||||
* wants one less than the true exponent.
|
||||
*/
|
||||
cExp -= 2;
|
||||
cSig = (cSig | 0x0010000000000000ULL) << 10;
|
||||
return roundAndPackFloat64(cSign ^ signflip, cExp, cSig STATUS_VAR);
|
||||
}
|
||||
return packFloat64(cSign ^ signflip, cExp, cSig);
|
||||
}
|
||||
|
||||
|
@ -4123,6 +4152,9 @@ float64 float64_muladd(float64 a, float64 b, float64 c, int flags STATUS_PARAM)
|
|||
if (!cSig) {
|
||||
/* Throw out the special case of c being an exact zero now */
|
||||
shift128RightJamming(pSig0, pSig1, 64, &pSig0, &pSig1);
|
||||
if (flags & float_muladd_halve_result) {
|
||||
pExp--;
|
||||
}
|
||||
return roundAndPackFloat64(zSign, pExp - 1,
|
||||
pSig1 STATUS_VAR);
|
||||
}
|
||||
|
@ -4159,6 +4191,9 @@ float64 float64_muladd(float64 a, float64 b, float64 c, int flags STATUS_PARAM)
|
|||
zExp--;
|
||||
}
|
||||
shift128RightJamming(zSig0, zSig1, 64, &zSig0, &zSig1);
|
||||
if (flags & float_muladd_halve_result) {
|
||||
zExp--;
|
||||
}
|
||||
return roundAndPackFloat64(zSign, zExp, zSig1 STATUS_VAR);
|
||||
} else {
|
||||
/* Subtraction */
|
||||
|
@ -4209,6 +4244,9 @@ float64 float64_muladd(float64 a, float64 b, float64 c, int flags STATUS_PARAM)
|
|||
zExp -= (shiftcount + 64);
|
||||
}
|
||||
}
|
||||
if (flags & float_muladd_halve_result) {
|
||||
zExp--;
|
||||
}
|
||||
return roundAndPackFloat64(zSign, zExp, zSig0 STATUS_VAR);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -224,27 +224,24 @@ static const VMStateDescription vmstate_pxa2xx_cm = {
|
|||
}
|
||||
};
|
||||
|
||||
static int pxa2xx_clkcfg_read(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t *value)
|
||||
static uint64_t pxa2xx_clkcfg_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
PXA2xxState *s = (PXA2xxState *)ri->opaque;
|
||||
*value = s->clkcfg;
|
||||
return 0;
|
||||
return s->clkcfg;
|
||||
}
|
||||
|
||||
static int pxa2xx_clkcfg_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
static void 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 int pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
static void pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
PXA2xxState *s = (PXA2xxState *)ri->opaque;
|
||||
static const char *pwrmode[8] = {
|
||||
|
@ -310,36 +307,29 @@ static int pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
printf("%s: machine entered %s mode\n", __func__,
|
||||
pwrmode[value & 7]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pxa2xx_cppmnc_read(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t *value)
|
||||
static uint64_t pxa2xx_cppmnc_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
PXA2xxState *s = (PXA2xxState *)ri->opaque;
|
||||
*value = s->pmnc;
|
||||
return 0;
|
||||
return s->pmnc;
|
||||
}
|
||||
|
||||
static int pxa2xx_cppmnc_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
static void 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)
|
||||
static uint64_t pxa2xx_cpccnt_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
PXA2xxState *s = (PXA2xxState *)ri->opaque;
|
||||
if (s->pmnc & 1) {
|
||||
*value = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
} else {
|
||||
*value = 0;
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const ARMCPRegInfo pxa_cp_reginfo[] = {
|
||||
|
|
|
@ -217,20 +217,17 @@ static const int pxa2xx_cp_reg_map[0x10] = {
|
|||
[0xa] = ICPR2,
|
||||
};
|
||||
|
||||
static int pxa2xx_pic_cp_read(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t *value)
|
||||
static uint64_t pxa2xx_pic_cp_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
int offset = pxa2xx_cp_reg_map[ri->crn];
|
||||
*value = pxa2xx_pic_mem_read(ri->opaque, offset, 4);
|
||||
return 0;
|
||||
return pxa2xx_pic_mem_read(ri->opaque, offset, 4);
|
||||
}
|
||||
|
||||
static int pxa2xx_pic_cp_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
static void pxa2xx_pic_cp_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
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) \
|
||||
|
|
|
@ -189,7 +189,7 @@ uint32_t gic_acknowledge_irq(GICState *s, int cpu)
|
|||
}
|
||||
s->last_active[irq][cpu] = s->running_irq[cpu];
|
||||
|
||||
if (s->revision == REV_11MPCORE) {
|
||||
if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) {
|
||||
/* Clear pending flags for both level and edge triggered interrupts.
|
||||
* Level triggered IRQs will be reasserted once they become inactive.
|
||||
*/
|
||||
|
|
|
@ -249,11 +249,14 @@ void float_raise( int8 flags STATUS_PARAM);
|
|||
| Using these differs from negating an input or output before calling
|
||||
| the muladd function in that this means that a NaN doesn't have its
|
||||
| sign bit inverted before it is propagated.
|
||||
| We also support halving the result before rounding, as a special
|
||||
| case to support the ARM fused-sqrt-step instruction FRSQRTS.
|
||||
*----------------------------------------------------------------------------*/
|
||||
enum {
|
||||
float_muladd_negate_c = 1,
|
||||
float_muladd_negate_product = 2,
|
||||
float_muladd_negate_result = 4,
|
||||
float_muladd_halve_result = 8,
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
|
|
|
@ -953,7 +953,8 @@ static int do_strex_a64(CPUARMState *env)
|
|||
goto finish;
|
||||
}
|
||||
}
|
||||
val = env->xregs[rt];
|
||||
/* handle the zero register */
|
||||
val = rt == 31 ? 0 : env->xregs[rt];
|
||||
switch (size) {
|
||||
case 0:
|
||||
segv = put_user_u8(val, addr);
|
||||
|
@ -972,7 +973,8 @@ static int do_strex_a64(CPUARMState *env)
|
|||
goto error;
|
||||
}
|
||||
if (is_pair) {
|
||||
val = env->xregs[rt2];
|
||||
/* handle the zero register */
|
||||
val = rt2 == 31 ? 0 : env->xregs[rt2];
|
||||
if (size == 2) {
|
||||
segv = put_user_u32(val, addr + 4);
|
||||
} else {
|
||||
|
|
|
@ -128,7 +128,7 @@ static void arm_cpu_reset(CPUState *s)
|
|||
}
|
||||
}
|
||||
|
||||
if (env->cp15.c1_sys & (1 << 13)) {
|
||||
if (env->cp15.c1_sys & SCTLR_V) {
|
||||
env->regs[15] = 0xFFFF0000;
|
||||
}
|
||||
|
||||
|
@ -681,14 +681,12 @@ static void cortex_a9_initfn(Object *obj)
|
|||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
static int a15_l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t *value)
|
||||
static uint64_t a15_l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
/* 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;
|
||||
return ((smp_cpus - 1) << 24) | (1 << 23);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
105
target-arm/cpu.h
105
target-arm/cpu.h
|
@ -217,11 +217,6 @@ typedef struct CPUARMState {
|
|||
uint32_t c15_power_control; /* power control */
|
||||
} cp15;
|
||||
|
||||
/* System registers (AArch64) */
|
||||
struct {
|
||||
uint64_t tpidr_el0;
|
||||
} sr;
|
||||
|
||||
struct {
|
||||
uint32_t other_sp;
|
||||
uint32_t vecbase;
|
||||
|
@ -337,6 +332,58 @@ int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address, int rw,
|
|||
int mmu_idx);
|
||||
#define cpu_handle_mmu_fault cpu_arm_handle_mmu_fault
|
||||
|
||||
/* SCTLR bit meanings. Several bits have been reused in newer
|
||||
* versions of the architecture; in that case we define constants
|
||||
* for both old and new bit meanings. Code which tests against those
|
||||
* bits should probably check or otherwise arrange that the CPU
|
||||
* is the architectural version it expects.
|
||||
*/
|
||||
#define SCTLR_M (1U << 0)
|
||||
#define SCTLR_A (1U << 1)
|
||||
#define SCTLR_C (1U << 2)
|
||||
#define SCTLR_W (1U << 3) /* up to v6; RAO in v7 */
|
||||
#define SCTLR_SA (1U << 3)
|
||||
#define SCTLR_P (1U << 4) /* up to v5; RAO in v6 and v7 */
|
||||
#define SCTLR_SA0 (1U << 4) /* v8 onward, AArch64 only */
|
||||
#define SCTLR_D (1U << 5) /* up to v5; RAO in v6 */
|
||||
#define SCTLR_CP15BEN (1U << 5) /* v7 onward */
|
||||
#define SCTLR_L (1U << 6) /* up to v5; RAO in v6 and v7; RAZ in v8 */
|
||||
#define SCTLR_B (1U << 7) /* up to v6; RAZ in v7 */
|
||||
#define SCTLR_ITD (1U << 7) /* v8 onward */
|
||||
#define SCTLR_S (1U << 8) /* up to v6; RAZ in v7 */
|
||||
#define SCTLR_SED (1U << 8) /* v8 onward */
|
||||
#define SCTLR_R (1U << 9) /* up to v6; RAZ in v7 */
|
||||
#define SCTLR_UMA (1U << 9) /* v8 onward, AArch64 only */
|
||||
#define SCTLR_F (1U << 10) /* up to v6 */
|
||||
#define SCTLR_SW (1U << 10) /* v7 onward */
|
||||
#define SCTLR_Z (1U << 11)
|
||||
#define SCTLR_I (1U << 12)
|
||||
#define SCTLR_V (1U << 13)
|
||||
#define SCTLR_RR (1U << 14) /* up to v7 */
|
||||
#define SCTLR_DZE (1U << 14) /* v8 onward, AArch64 only */
|
||||
#define SCTLR_L4 (1U << 15) /* up to v6; RAZ in v7 */
|
||||
#define SCTLR_UCT (1U << 15) /* v8 onward, AArch64 only */
|
||||
#define SCTLR_DT (1U << 16) /* up to ??, RAO in v6 and v7 */
|
||||
#define SCTLR_nTWI (1U << 16) /* v8 onward */
|
||||
#define SCTLR_HA (1U << 17)
|
||||
#define SCTLR_IT (1U << 18) /* up to ??, RAO in v6 and v7 */
|
||||
#define SCTLR_nTWE (1U << 18) /* v8 onward */
|
||||
#define SCTLR_WXN (1U << 19)
|
||||
#define SCTLR_ST (1U << 20) /* up to ??, RAZ in v6 */
|
||||
#define SCTLR_UWXN (1U << 20) /* v7 onward */
|
||||
#define SCTLR_FI (1U << 21)
|
||||
#define SCTLR_U (1U << 22)
|
||||
#define SCTLR_XP (1U << 23) /* up to v6; v7 onward RAO */
|
||||
#define SCTLR_VE (1U << 24) /* up to v7 */
|
||||
#define SCTLR_E0E (1U << 24) /* v8 onward, AArch64 only */
|
||||
#define SCTLR_EE (1U << 25)
|
||||
#define SCTLR_L2 (1U << 26) /* up to v6, RAZ in v7 */
|
||||
#define SCTLR_UCI (1U << 26) /* v8 onward, AArch64 only */
|
||||
#define SCTLR_NMFI (1U << 27)
|
||||
#define SCTLR_TRE (1U << 28)
|
||||
#define SCTLR_AFE (1U << 29)
|
||||
#define SCTLR_TE (1U << 30)
|
||||
|
||||
#define CPSR_M (0x1fU)
|
||||
#define CPSR_T (1U << 5)
|
||||
#define CPSR_F (1U << 6)
|
||||
|
@ -764,14 +811,30 @@ static inline int arm_current_pl(CPUARMState *env)
|
|||
|
||||
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 enum CPAccessResult {
|
||||
/* Access is permitted */
|
||||
CP_ACCESS_OK = 0,
|
||||
/* Access fails due to a configurable trap or enable which would
|
||||
* result in a categorized exception syndrome giving information about
|
||||
* the failing instruction (ie syndrome category 0x3, 0x4, 0x5, 0x6,
|
||||
* 0xc or 0x18).
|
||||
*/
|
||||
CP_ACCESS_TRAP = 1,
|
||||
/* Access fails and results in an exception syndrome 0x0 ("uncategorized").
|
||||
* Note that this is not a catch-all case -- the set of cases which may
|
||||
* result in this failure is specifically defined by the architecture.
|
||||
*/
|
||||
CP_ACCESS_TRAP_UNCATEGORIZED = 2,
|
||||
} CPAccessResult;
|
||||
|
||||
/* Access functions for coprocessor registers. These cannot fail and
|
||||
* may not raise exceptions.
|
||||
*/
|
||||
typedef int CPReadFn(CPUARMState *env, const ARMCPRegInfo *opaque,
|
||||
uint64_t *value);
|
||||
typedef int CPWriteFn(CPUARMState *env, const ARMCPRegInfo *opaque,
|
||||
uint64_t value);
|
||||
typedef uint64_t CPReadFn(CPUARMState *env, const ARMCPRegInfo *opaque);
|
||||
typedef void CPWriteFn(CPUARMState *env, const ARMCPRegInfo *opaque,
|
||||
uint64_t value);
|
||||
/* Access permission check functions for coprocessor registers. */
|
||||
typedef CPAccessResult CPAccessFn(CPUARMState *env, const ARMCPRegInfo *opaque);
|
||||
/* Hook function for register reset */
|
||||
typedef void CPResetFn(CPUARMState *env, const ARMCPRegInfo *opaque);
|
||||
|
||||
|
@ -825,6 +888,12 @@ struct ARMCPRegInfo {
|
|||
* 2. both readfn and writefn are specified
|
||||
*/
|
||||
ptrdiff_t fieldoffset; /* offsetof(CPUARMState, field) */
|
||||
/* Function for making any access checks for this register in addition to
|
||||
* those specified by the 'access' permissions bits. If NULL, no extra
|
||||
* checks required. The access check is performed at runtime, not at
|
||||
* translate time.
|
||||
*/
|
||||
CPAccessFn *accessfn;
|
||||
/* Function for handling reads of this register. If NULL, then reads
|
||||
* will be done by loading from the offset into CPUARMState specified
|
||||
* by fieldoffset.
|
||||
|
@ -838,14 +907,14 @@ struct ARMCPRegInfo {
|
|||
/* Function for doing a "raw" read; used when we need to copy
|
||||
* coprocessor state to the kernel for KVM or out for
|
||||
* migration. This only needs to be provided if there is also a
|
||||
* readfn and it makes an access permission check.
|
||||
* readfn and it has side effects (for instance clear-on-read bits).
|
||||
*/
|
||||
CPReadFn *raw_readfn;
|
||||
/* Function for doing a "raw" write; used when we need to copy KVM
|
||||
* kernel coprocessor state into userspace, or for inbound
|
||||
* migration. This only needs to be provided if there is also a
|
||||
* writefn and it makes an access permission check or masks out
|
||||
* "unwritable" bits or has write-one-to-clear or similar behaviour.
|
||||
* writefn and it masks out "unwritable" bits or has write-one-to-clear
|
||||
* or similar behaviour.
|
||||
*/
|
||||
CPWriteFn *raw_writefn;
|
||||
/* Function for resetting the register. If NULL, then reset will be done
|
||||
|
@ -880,10 +949,10 @@ static inline void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *regs)
|
|||
const ARMCPRegInfo *get_arm_cp_reginfo(GHashTable *cpregs, 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);
|
||||
void 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);
|
||||
uint64_t arm_cp_read_zero(CPUARMState *env, const ARMCPRegInfo *ri);
|
||||
|
||||
/* CPResetFn that does nothing, for use if no reset is required even
|
||||
* if fieldoffset is non zero.
|
||||
|
|
|
@ -123,6 +123,32 @@ uint64_t HELPER(vfp_cmped_a64)(float64 x, float64 y, void *fp_status)
|
|||
return float_rel_to_flags(float64_compare(x, y, fp_status));
|
||||
}
|
||||
|
||||
float32 HELPER(vfp_mulxs)(float32 a, float32 b, void *fpstp)
|
||||
{
|
||||
float_status *fpst = fpstp;
|
||||
|
||||
if ((float32_is_zero(a) && float32_is_infinity(b)) ||
|
||||
(float32_is_infinity(a) && float32_is_zero(b))) {
|
||||
/* 2.0 with the sign bit set to sign(A) XOR sign(B) */
|
||||
return make_float32((1U << 30) |
|
||||
((float32_val(a) ^ float32_val(b)) & (1U << 31)));
|
||||
}
|
||||
return float32_mul(a, b, fpst);
|
||||
}
|
||||
|
||||
float64 HELPER(vfp_mulxd)(float64 a, float64 b, void *fpstp)
|
||||
{
|
||||
float_status *fpst = fpstp;
|
||||
|
||||
if ((float64_is_zero(a) && float64_is_infinity(b)) ||
|
||||
(float64_is_infinity(a) && float64_is_zero(b))) {
|
||||
/* 2.0 with the sign bit set to sign(A) XOR sign(B) */
|
||||
return make_float64((1ULL << 62) |
|
||||
((float64_val(a) ^ float64_val(b)) & (1ULL << 63)));
|
||||
}
|
||||
return float64_mul(a, b, fpst);
|
||||
}
|
||||
|
||||
uint64_t HELPER(simd_tbl)(CPUARMState *env, uint64_t result, uint64_t indices,
|
||||
uint32_t rn, uint32_t numregs)
|
||||
{
|
||||
|
@ -153,3 +179,82 @@ uint64_t HELPER(simd_tbl)(CPUARMState *env, uint64_t result, uint64_t indices,
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* 64bit/double versions of the neon float compare functions */
|
||||
uint64_t HELPER(neon_ceq_f64)(float64 a, float64 b, void *fpstp)
|
||||
{
|
||||
float_status *fpst = fpstp;
|
||||
return -float64_eq_quiet(a, b, fpst);
|
||||
}
|
||||
|
||||
uint64_t HELPER(neon_cge_f64)(float64 a, float64 b, void *fpstp)
|
||||
{
|
||||
float_status *fpst = fpstp;
|
||||
return -float64_le(b, a, fpst);
|
||||
}
|
||||
|
||||
uint64_t HELPER(neon_cgt_f64)(float64 a, float64 b, void *fpstp)
|
||||
{
|
||||
float_status *fpst = fpstp;
|
||||
return -float64_lt(b, a, fpst);
|
||||
}
|
||||
|
||||
/* Reciprocal step and sqrt step. Note that unlike the A32/T32
|
||||
* versions, these do a fully fused multiply-add or
|
||||
* multiply-add-and-halve.
|
||||
*/
|
||||
#define float32_two make_float32(0x40000000)
|
||||
#define float32_three make_float32(0x40400000)
|
||||
#define float32_one_point_five make_float32(0x3fc00000)
|
||||
|
||||
#define float64_two make_float64(0x4000000000000000ULL)
|
||||
#define float64_three make_float64(0x4008000000000000ULL)
|
||||
#define float64_one_point_five make_float64(0x3FF8000000000000ULL)
|
||||
|
||||
float32 HELPER(recpsf_f32)(float32 a, float32 b, void *fpstp)
|
||||
{
|
||||
float_status *fpst = fpstp;
|
||||
|
||||
a = float32_chs(a);
|
||||
if ((float32_is_infinity(a) && float32_is_zero(b)) ||
|
||||
(float32_is_infinity(b) && float32_is_zero(a))) {
|
||||
return float32_two;
|
||||
}
|
||||
return float32_muladd(a, b, float32_two, 0, fpst);
|
||||
}
|
||||
|
||||
float64 HELPER(recpsf_f64)(float64 a, float64 b, void *fpstp)
|
||||
{
|
||||
float_status *fpst = fpstp;
|
||||
|
||||
a = float64_chs(a);
|
||||
if ((float64_is_infinity(a) && float64_is_zero(b)) ||
|
||||
(float64_is_infinity(b) && float64_is_zero(a))) {
|
||||
return float64_two;
|
||||
}
|
||||
return float64_muladd(a, b, float64_two, 0, fpst);
|
||||
}
|
||||
|
||||
float32 HELPER(rsqrtsf_f32)(float32 a, float32 b, void *fpstp)
|
||||
{
|
||||
float_status *fpst = fpstp;
|
||||
|
||||
a = float32_chs(a);
|
||||
if ((float32_is_infinity(a) && float32_is_zero(b)) ||
|
||||
(float32_is_infinity(b) && float32_is_zero(a))) {
|
||||
return float32_one_point_five;
|
||||
}
|
||||
return float32_muladd(a, b, float32_three, float_muladd_halve_result, fpst);
|
||||
}
|
||||
|
||||
float64 HELPER(rsqrtsf_f64)(float64 a, float64 b, void *fpstp)
|
||||
{
|
||||
float_status *fpst = fpstp;
|
||||
|
||||
a = float64_chs(a);
|
||||
if ((float64_is_infinity(a) && float64_is_zero(b)) ||
|
||||
(float64_is_infinity(b) && float64_is_zero(a))) {
|
||||
return float64_one_point_five;
|
||||
}
|
||||
return float64_muladd(a, b, float64_three, float_muladd_halve_result, fpst);
|
||||
}
|
||||
|
|
|
@ -27,3 +27,12 @@ DEF_HELPER_3(vfp_cmpes_a64, i64, f32, f32, ptr)
|
|||
DEF_HELPER_3(vfp_cmpd_a64, i64, f64, f64, ptr)
|
||||
DEF_HELPER_3(vfp_cmped_a64, i64, f64, f64, ptr)
|
||||
DEF_HELPER_FLAGS_5(simd_tbl, TCG_CALL_NO_RWG_SE, i64, env, i64, i64, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(vfp_mulxs, TCG_CALL_NO_RWG, f32, f32, f32, ptr)
|
||||
DEF_HELPER_FLAGS_3(vfp_mulxd, TCG_CALL_NO_RWG, f64, f64, f64, ptr)
|
||||
DEF_HELPER_FLAGS_3(neon_ceq_f64, TCG_CALL_NO_RWG, i64, i64, i64, ptr)
|
||||
DEF_HELPER_FLAGS_3(neon_cge_f64, TCG_CALL_NO_RWG, i64, i64, i64, ptr)
|
||||
DEF_HELPER_FLAGS_3(neon_cgt_f64, TCG_CALL_NO_RWG, i64, i64, i64, ptr)
|
||||
DEF_HELPER_FLAGS_3(recpsf_f32, TCG_CALL_NO_RWG, f32, f32, f32, ptr)
|
||||
DEF_HELPER_FLAGS_3(recpsf_f64, TCG_CALL_NO_RWG, f64, f64, f64, ptr)
|
||||
DEF_HELPER_FLAGS_3(rsqrtsf_f32, TCG_CALL_NO_RWG, f32, f32, f32, ptr)
|
||||
DEF_HELPER_FLAGS_3(rsqrtsf_f64, TCG_CALL_NO_RWG, f64, f64, f64, ptr)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -57,6 +57,7 @@ DEF_HELPER_1(cpsr_read, i32, env)
|
|||
DEF_HELPER_3(v7m_msr, void, env, i32, i32)
|
||||
DEF_HELPER_2(v7m_mrs, i32, env, i32)
|
||||
|
||||
DEF_HELPER_2(access_check_cp_reg, void, env, ptr)
|
||||
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)
|
||||
|
@ -382,6 +383,8 @@ DEF_HELPER_3(neon_cge_f32, i32, i32, i32, ptr)
|
|||
DEF_HELPER_3(neon_cgt_f32, i32, i32, i32, ptr)
|
||||
DEF_HELPER_3(neon_acge_f32, i32, i32, i32, ptr)
|
||||
DEF_HELPER_3(neon_acgt_f32, i32, i32, i32, ptr)
|
||||
DEF_HELPER_3(neon_acge_f64, i64, i64, i64, ptr)
|
||||
DEF_HELPER_3(neon_acgt_f64, i64, i64, i64, ptr)
|
||||
|
||||
/* iwmmxt_helper.c */
|
||||
DEF_HELPER_2(iwmmxt_maddsq, i64, i64, i64)
|
||||
|
|
|
@ -50,15 +50,29 @@ MISMATCH_CHECK(PSCI_FN_CPU_OFF, KVM_PSCI_FN_CPU_OFF)
|
|||
MISMATCH_CHECK(PSCI_FN_CPU_ON, KVM_PSCI_FN_CPU_ON)
|
||||
MISMATCH_CHECK(PSCI_FN_MIGRATE, KVM_PSCI_FN_MIGRATE)
|
||||
|
||||
/* Note that KVM uses overlapping values for AArch32 and AArch64
|
||||
* target CPU numbers. AArch32 targets:
|
||||
*/
|
||||
#define QEMU_KVM_ARM_TARGET_CORTEX_A15 0
|
||||
#define QEMU_KVM_ARM_TARGET_CORTEX_A7 1
|
||||
|
||||
/* AArch64 targets: */
|
||||
#define QEMU_KVM_ARM_TARGET_AEM_V8 0
|
||||
#define QEMU_KVM_ARM_TARGET_FOUNDATION_V8 1
|
||||
#define QEMU_KVM_ARM_TARGET_CORTEX_A57 2
|
||||
|
||||
/* There's no kernel define for this: sentinel value which
|
||||
* matches no KVM target value for either 64 or 32 bit
|
||||
*/
|
||||
#define QEMU_KVM_ARM_TARGET_NONE UINT_MAX
|
||||
|
||||
#ifndef TARGET_AARCH64
|
||||
#ifdef TARGET_AARCH64
|
||||
MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_AEM_V8, KVM_ARM_TARGET_AEM_V8)
|
||||
MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_FOUNDATION_V8, KVM_ARM_TARGET_FOUNDATION_V8)
|
||||
MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A57, KVM_ARM_TARGET_CORTEX_A57)
|
||||
#else
|
||||
MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A15, KVM_ARM_TARGET_CORTEX_A15)
|
||||
MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A7, KVM_ARM_TARGET_CORTEX_A7)
|
||||
#endif
|
||||
|
||||
#define CP_REG_ARM64 0x6000000000000000ULL
|
||||
|
|
|
@ -1823,6 +1823,22 @@ uint32_t HELPER(neon_acgt_f32)(uint32_t a, uint32_t b, void *fpstp)
|
|||
return -float32_lt(f1, f0, fpst);
|
||||
}
|
||||
|
||||
uint64_t HELPER(neon_acge_f64)(uint64_t a, uint64_t b, void *fpstp)
|
||||
{
|
||||
float_status *fpst = fpstp;
|
||||
float64 f0 = float64_abs(make_float64(a));
|
||||
float64 f1 = float64_abs(make_float64(b));
|
||||
return -float64_le(f1, f0, fpst);
|
||||
}
|
||||
|
||||
uint64_t HELPER(neon_acgt_f64)(uint64_t a, uint64_t b, void *fpstp)
|
||||
{
|
||||
float_status *fpst = fpstp;
|
||||
float64 f0 = float64_abs(make_float64(a));
|
||||
float64 f1 = float64_abs(make_float64(b));
|
||||
return -float64_lt(f1, f0, fpst);
|
||||
}
|
||||
|
||||
#define ELEM(V, N, SIZE) (((V) >> ((N) * (SIZE))) & ((1ull << (SIZE)) - 1))
|
||||
|
||||
void HELPER(neon_qunzip8)(CPUARMState *env, uint32_t rd, uint32_t rm)
|
||||
|
|
|
@ -273,44 +273,50 @@ void HELPER(set_user_reg)(CPUARMState *env, uint32_t regno, uint32_t val)
|
|||
}
|
||||
}
|
||||
|
||||
void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip)
|
||||
{
|
||||
const ARMCPRegInfo *ri = rip;
|
||||
switch (ri->accessfn(env, ri)) {
|
||||
case CP_ACCESS_OK:
|
||||
return;
|
||||
case CP_ACCESS_TRAP:
|
||||
case CP_ACCESS_TRAP_UNCATEGORIZED:
|
||||
/* These cases will eventually need to generate different
|
||||
* syndrome information.
|
||||
*/
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
raise_exception(env, EXCP_UDEF);
|
||||
}
|
||||
|
||||
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(env, excp);
|
||||
}
|
||||
|
||||
ri->writefn(env, ri, value);
|
||||
}
|
||||
|
||||
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(env, excp);
|
||||
}
|
||||
return value;
|
||||
|
||||
return ri->readfn(env, ri);
|
||||
}
|
||||
|
||||
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(env, excp);
|
||||
}
|
||||
|
||||
ri->writefn(env, ri, value);
|
||||
}
|
||||
|
||||
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(env, excp);
|
||||
}
|
||||
return value;
|
||||
|
||||
return ri->readfn(env, ri);
|
||||
}
|
||||
|
||||
/* ??? Flag setting arithmetic is awkward because we need to do comparisons.
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -6837,6 +6837,17 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (ri->accessfn) {
|
||||
/* Emit code to perform further access permissions checks at
|
||||
* runtime; this may result in an exception.
|
||||
*/
|
||||
TCGv_ptr tmpptr;
|
||||
gen_set_pc_im(s, s->pc);
|
||||
tmpptr = tcg_const_ptr(ri);
|
||||
gen_helper_access_check_cp_reg(cpu_env, tmpptr);
|
||||
tcg_temp_free_ptr(tmpptr);
|
||||
}
|
||||
|
||||
/* Handle special cases first */
|
||||
switch (ri->type & ~(ARM_CP_FLAG_MASK & ~ARM_CP_SPECIAL)) {
|
||||
case ARM_CP_NOP:
|
||||
|
@ -6865,7 +6876,6 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
|
|||
tmp64 = tcg_const_i64(ri->resetvalue);
|
||||
} else if (ri->readfn) {
|
||||
TCGv_ptr tmpptr;
|
||||
gen_set_pc_im(s, s->pc);
|
||||
tmp64 = tcg_temp_new_i64();
|
||||
tmpptr = tcg_const_ptr(ri);
|
||||
gen_helper_get_cp_reg64(tmp64, cpu_env, tmpptr);
|
||||
|
@ -6888,7 +6898,6 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
|
|||
tmp = tcg_const_i32(ri->resetvalue);
|
||||
} else if (ri->readfn) {
|
||||
TCGv_ptr tmpptr;
|
||||
gen_set_pc_im(s, s->pc);
|
||||
tmp = tcg_temp_new_i32();
|
||||
tmpptr = tcg_const_ptr(ri);
|
||||
gen_helper_get_cp_reg(tmp, cpu_env, tmpptr);
|
||||
|
@ -6923,7 +6932,6 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
|
|||
tcg_temp_free_i32(tmphi);
|
||||
if (ri->writefn) {
|
||||
TCGv_ptr tmpptr = tcg_const_ptr(ri);
|
||||
gen_set_pc_im(s, s->pc);
|
||||
gen_helper_set_cp_reg64(cpu_env, tmpptr, tmp64);
|
||||
tcg_temp_free_ptr(tmpptr);
|
||||
} else {
|
||||
|
@ -6934,7 +6942,6 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
|
|||
if (ri->writefn) {
|
||||
TCGv_i32 tmp;
|
||||
TCGv_ptr tmpptr;
|
||||
gen_set_pc_im(s, s->pc);
|
||||
tmp = load_reg(s, rt);
|
||||
tmpptr = tcg_const_ptr(ri);
|
||||
gen_helper_set_cp_reg(cpu_env, tmpptr, tmp);
|
||||
|
@ -6962,6 +6969,19 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Unknown register; this might be a guest error or a QEMU
|
||||
* unimplemented feature.
|
||||
*/
|
||||
if (is64) {
|
||||
qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 "
|
||||
"64 bit system register cp:%d opc1: %d crm:%d\n",
|
||||
isread ? "read" : "write", cpnum, opc1, crm);
|
||||
} else {
|
||||
qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 "
|
||||
"system register cp:%d opc1:%d crn:%d crm:%d opc2:%d\n",
|
||||
isread ? "read" : "write", cpnum, opc1, crn, crm, opc2);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue