diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2018-11-08 14:42:37 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2018-11-08 14:42:37 +0000 |
commit | 7360be896a928d9c75894f34e8e620b82bbc1676 (patch) | |
tree | ae82cde790749925eb4262cde1f4ab45ac4dd892 /target | |
parent | 0b57007755c2ee442740b5321ffc7072aed88714 (diff) | |
parent | b9a477b725788e47bf653eab36e64f232d259f2a (diff) | |
download | qemu-7360be896a928d9c75894f34e8e620b82bbc1676.zip |
Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-3.1-20181108' into staging
ppc patch queue 2018-11-08
Here's another patch of accumulated ppc patches for qemu-3.1.
Highlights are:
* Support for nested HV KVM on POWER9 hosts
* Remove Alex Graf as ppc maintainer
* Emulation of external PID instructions
# gpg: Signature made Thu 08 Nov 2018 12:14:27 GMT
# gpg: using RSA key 6C38CACA20D9B392
# gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>"
# gpg: aka "David Gibson (Red Hat) <dgibson@redhat.com>"
# gpg: aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>"
# gpg: aka "David Gibson (kernel.org) <dwg@kernel.org>"
# Primary key fingerprint: 75F4 6586 AE61 A66C C44E 87DC 6C38 CACA 20D9 B392
* remotes/dgibson/tags/ppc-for-3.1-20181108: (22 commits)
ppc/spapr_caps: Add SPAPR_CAP_NESTED_KVM_HV
target/ppc: Add one reg id for ptcr
This patch fixes processing of rfi instructions in icount mode.
hw/ppc/ppc440_uc: Remove dead code in sdram_size()
MAINTAINERS: PPC: Remove myself
ppc/pnv: check size before data buffer access
target/ppc: fix mtmsr instruction for icount
hw/ppc/mac_newworld: Free openpic_irqs array after use
macio/pmu: Fix missing vmsd terminator
spapr_pci: convert g_malloc() to g_new()
target/ppc: Split out float_invalid_cvt
target/ppc: Split out float_invalid_op_div
target/ppc: Split out float_invalid_op_mul
target/ppc: Split out float_invalid_op_addsub
target/ppc: Introduce fp number classification
target/ppc: Remove float_check_status
target/ppc: Split up float_invalid_op_excp
hw/ppc/spapr_rng: Introduce CONFIG_SPAPR_RNG switch for spapr_rng.c
PPC: e500: convert SysBus init method to a realize method
ppc4xx_pci: convert SysBus init method to a realize method
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target')
-rw-r--r-- | target/ppc/cpu.h | 24 | ||||
-rw-r--r-- | target/ppc/fpu_helper.c | 661 | ||||
-rw-r--r-- | target/ppc/helper.h | 4 | ||||
-rw-r--r-- | target/ppc/kvm.c | 12 | ||||
-rw-r--r-- | target/ppc/kvm_ppc.h | 12 | ||||
-rw-r--r-- | target/ppc/mem_helper.c | 34 | ||||
-rw-r--r-- | target/ppc/mmu_helper.c | 172 | ||||
-rw-r--r-- | target/ppc/translate.c | 165 | ||||
-rw-r--r-- | target/ppc/translate/fp-impl.inc.c | 34 | ||||
-rw-r--r-- | target/ppc/translate/fp-ops.inc.c | 2 | ||||
-rw-r--r-- | target/ppc/translate_init.inc.c | 31 |
11 files changed, 767 insertions, 384 deletions
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index b5b8f6f440..ab68abe8a2 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -918,6 +918,19 @@ enum { /* number of possible TLBs */ #define BOOKE206_MAX_TLBN 4 +#define EPID_EPID_SHIFT 0x0 +#define EPID_EPID 0xFF +#define EPID_ELPID_SHIFT 0x10 +#define EPID_ELPID 0x3F0000 +#define EPID_EGS 0x20000000 +#define EPID_EGS_SHIFT 29 +#define EPID_EAS 0x40000000 +#define EPID_EAS_SHIFT 30 +#define EPID_EPR 0x80000000 +#define EPID_EPR_SHIFT 31 +/* We don't support EGS and ELPID */ +#define EPID_MASK (EPID_EPID | EPID_EAS | EPID_EPR) + /*****************************************************************************/ /* Server and Embedded Processor Control */ @@ -947,7 +960,16 @@ struct ppc_radix_page_info { /*****************************************************************************/ /* The whole PowerPC CPU context */ -#define NB_MMU_MODES 8 + +/* PowerPC needs eight modes for different hypervisor/supervisor/guest + + * real/paged mode combinations. The other two modes are for external PID + * load/store. + */ +#define NB_MMU_MODES 10 +#define MMU_MODE8_SUFFIX _epl +#define MMU_MODE9_SUFFIX _eps +#define PPC_TLB_EPID_LOAD 8 +#define PPC_TLB_EPID_STORE 9 #define PPC_CPU_OPCODES_LEN 0x40 #define PPC_CPU_INDIRECT_OPCODES_LEN 0x20 diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index b9bb1b856e..2ed4f42275 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -114,54 +114,62 @@ static inline int ppc_float64_get_unbiased_exp(float64 f) return ((f >> 52) & 0x7FF) - 1023; } -#define COMPUTE_FPRF(tp) \ -void helper_compute_fprf_##tp(CPUPPCState *env, tp arg) \ +/* Classify a floating-point number. */ +enum { + is_normal = 1, + is_zero = 2, + is_denormal = 4, + is_inf = 8, + is_qnan = 16, + is_snan = 32, + is_neg = 64, +}; + +#define COMPUTE_CLASS(tp) \ +static int tp##_classify(tp arg) \ { \ - int isneg; \ - int fprf; \ - \ - isneg = tp##_is_neg(arg); \ + int ret = tp##_is_neg(arg) * is_neg; \ if (unlikely(tp##_is_any_nan(arg))) { \ - if (tp##_is_signaling_nan(arg, &env->fp_status)) { \ - /* Signaling NaN: flags are undefined */ \ - fprf = 0x00; \ - } else { \ - /* Quiet NaN */ \ - fprf = 0x11; \ - } \ + float_status dummy = { }; /* snan_bit_is_one = 0 */ \ + ret |= (tp##_is_signaling_nan(arg, &dummy) \ + ? is_snan : is_qnan); \ } else if (unlikely(tp##_is_infinity(arg))) { \ - /* +/- infinity */ \ - if (isneg) { \ - fprf = 0x09; \ - } else { \ - fprf = 0x05; \ - } \ + ret |= is_inf; \ + } else if (tp##_is_zero(arg)) { \ + ret |= is_zero; \ + } else if (tp##_is_zero_or_denormal(arg)) { \ + ret |= is_denormal; \ } else { \ - if (tp##_is_zero(arg)) { \ - /* +/- zero */ \ - if (isneg) { \ - fprf = 0x12; \ - } else { \ - fprf = 0x02; \ - } \ - } else { \ - if (tp##_is_zero_or_denormal(arg)) { \ - /* Denormalized numbers */ \ - fprf = 0x10; \ - } else { \ - /* Normalized numbers */ \ - fprf = 0x00; \ - } \ - if (isneg) { \ - fprf |= 0x08; \ - } else { \ - fprf |= 0x04; \ - } \ - } \ + ret |= is_normal; \ } \ - /* We update FPSCR_FPRF */ \ - env->fpscr &= ~(0x1F << FPSCR_FPRF); \ - env->fpscr |= fprf << FPSCR_FPRF; \ + return ret; \ +} + +COMPUTE_CLASS(float16) +COMPUTE_CLASS(float32) +COMPUTE_CLASS(float64) +COMPUTE_CLASS(float128) + +static void set_fprf_from_class(CPUPPCState *env, int class) +{ + static const uint8_t fprf[6][2] = { + { 0x04, 0x08 }, /* normalized */ + { 0x02, 0x12 }, /* zero */ + { 0x14, 0x18 }, /* denormalized */ + { 0x05, 0x09 }, /* infinity */ + { 0x11, 0x11 }, /* qnan */ + { 0x00, 0x00 }, /* snan -- flags are undefined */ + }; + bool isneg = class & is_neg; + + env->fpscr &= ~(0x1F << FPSCR_FPRF); + env->fpscr |= fprf[ctz32(class)][isneg] << FPSCR_FPRF; +} + +#define COMPUTE_FPRF(tp) \ +void helper_compute_fprf_##tp(CPUPPCState *env, tp arg) \ +{ \ + set_fprf_from_class(env, tp##_classify(arg)); \ } COMPUTE_FPRF(float16) @@ -170,96 +178,120 @@ COMPUTE_FPRF(float64) COMPUTE_FPRF(float128) /* Floating-point invalid operations exception */ -static inline __attribute__((__always_inline__)) -uint64_t float_invalid_op_excp(CPUPPCState *env, int op, int set_fpcc) +static void finish_invalid_op_excp(CPUPPCState *env, int op, uintptr_t retaddr) { - CPUState *cs = CPU(ppc_env_get_cpu(env)); - uint64_t ret = 0; - int ve; + /* Update the floating-point invalid operation summary */ + env->fpscr |= 1 << FPSCR_VX; + /* Update the floating-point exception summary */ + env->fpscr |= FP_FX; + if (fpscr_ve != 0) { + /* Update the floating-point enabled exception summary */ + env->fpscr |= 1 << FPSCR_FEX; + if (fp_exceptions_enabled(env)) { + raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_FP | op, retaddr); + } + } +} - ve = fpscr_ve; - switch (op) { - case POWERPC_EXCP_FP_VXSNAN: - env->fpscr |= 1 << FPSCR_VXSNAN; - break; - case POWERPC_EXCP_FP_VXSOFT: - env->fpscr |= 1 << FPSCR_VXSOFT; - break; - case POWERPC_EXCP_FP_VXISI: - /* Magnitude subtraction of infinities */ - env->fpscr |= 1 << FPSCR_VXISI; - goto update_arith; - case POWERPC_EXCP_FP_VXIDI: - /* Division of infinity by infinity */ - env->fpscr |= 1 << FPSCR_VXIDI; - goto update_arith; - case POWERPC_EXCP_FP_VXZDZ: - /* Division of zero by zero */ - env->fpscr |= 1 << FPSCR_VXZDZ; - goto update_arith; - case POWERPC_EXCP_FP_VXIMZ: - /* Multiplication of zero by infinity */ - env->fpscr |= 1 << FPSCR_VXIMZ; - goto update_arith; - case POWERPC_EXCP_FP_VXVC: - /* Ordered comparison of NaN */ - env->fpscr |= 1 << FPSCR_VXVC; +static void finish_invalid_op_arith(CPUPPCState *env, int op, + bool set_fpcc, uintptr_t retaddr) +{ + env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); + if (fpscr_ve == 0) { if (set_fpcc) { env->fpscr &= ~(0xF << FPSCR_FPCC); env->fpscr |= 0x11 << FPSCR_FPCC; } - /* We must update the target FPR before raising the exception */ - if (ve != 0) { - cs->exception_index = POWERPC_EXCP_PROGRAM; - env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC; - /* Update the floating-point enabled exception summary */ - env->fpscr |= 1 << FPSCR_FEX; - /* Exception is differed */ - ve = 0; - } - break; - case POWERPC_EXCP_FP_VXSQRT: - /* Square root of a negative number */ - env->fpscr |= 1 << FPSCR_VXSQRT; - update_arith: - env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); - if (ve == 0) { - /* Set the result to quiet NaN */ - ret = 0x7FF8000000000000ULL; - if (set_fpcc) { - env->fpscr &= ~(0xF << FPSCR_FPCC); - env->fpscr |= 0x11 << FPSCR_FPCC; - } - } - break; - case POWERPC_EXCP_FP_VXCVI: - /* Invalid conversion */ - env->fpscr |= 1 << FPSCR_VXCVI; - env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); - if (ve == 0) { - /* Set the result to quiet NaN */ - ret = 0x7FF8000000000000ULL; - if (set_fpcc) { - env->fpscr &= ~(0xF << FPSCR_FPCC); - env->fpscr |= 0x11 << FPSCR_FPCC; - } - } - break; + } + finish_invalid_op_excp(env, op, retaddr); +} + +/* Signalling NaN */ +static void float_invalid_op_vxsnan(CPUPPCState *env, uintptr_t retaddr) +{ + env->fpscr |= 1 << FPSCR_VXSNAN; + finish_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, retaddr); +} + +/* Magnitude subtraction of infinities */ +static void float_invalid_op_vxisi(CPUPPCState *env, bool set_fpcc, + uintptr_t retaddr) +{ + env->fpscr |= 1 << FPSCR_VXISI; + finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXISI, set_fpcc, retaddr); +} + +/* Division of infinity by infinity */ +static void float_invalid_op_vxidi(CPUPPCState *env, bool set_fpcc, + uintptr_t retaddr) +{ + env->fpscr |= 1 << FPSCR_VXIDI; + finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXIDI, set_fpcc, retaddr); +} + +/* Division of zero by zero */ +static void float_invalid_op_vxzdz(CPUPPCState *env, bool set_fpcc, + uintptr_t retaddr) +{ + env->fpscr |= 1 << FPSCR_VXZDZ; + finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXZDZ, set_fpcc, retaddr); +} + +/* Multiplication of zero by infinity */ +static void float_invalid_op_vximz(CPUPPCState *env, bool set_fpcc, + uintptr_t retaddr) +{ + env->fpscr |= 1 << FPSCR_VXIMZ; + finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXIMZ, set_fpcc, retaddr); +} + +/* Square root of a negative number */ +static void float_invalid_op_vxsqrt(CPUPPCState *env, bool set_fpcc, + uintptr_t retaddr) +{ + env->fpscr |= 1 << FPSCR_VXSQRT; + finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXSQRT, set_fpcc, retaddr); +} + +/* Ordered comparison of NaN */ +static void float_invalid_op_vxvc(CPUPPCState *env, bool set_fpcc, + uintptr_t retaddr) +{ + env->fpscr |= 1 << FPSCR_VXVC; + if (set_fpcc) { + env->fpscr &= ~(0xF << FPSCR_FPCC); + env->fpscr |= 0x11 << FPSCR_FPCC; } /* Update the floating-point invalid operation summary */ env->fpscr |= 1 << FPSCR_VX; /* Update the floating-point exception summary */ env->fpscr |= FP_FX; - if (ve != 0) { + /* We must update the target FPR before raising the exception */ + if (fpscr_ve != 0) { + CPUState *cs = CPU(ppc_env_get_cpu(env)); + + cs->exception_index = POWERPC_EXCP_PROGRAM; + env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC; /* Update the floating-point enabled exception summary */ env->fpscr |= 1 << FPSCR_FEX; - if (fp_exceptions_enabled(env)) { - /* GETPC() works here because this is inline */ - raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_FP | op, GETPC()); + /* Exception is differed */ + } +} + +/* Invalid conversion */ +static void float_invalid_op_vxcvi(CPUPPCState *env, bool set_fpcc, + uintptr_t retaddr) +{ + env->fpscr |= 1 << FPSCR_VXCVI; + env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); + if (fpscr_ve == 0) { + if (set_fpcc) { + env->fpscr &= ~(0xF << FPSCR_FPCC); + env->fpscr |= 0x11 << FPSCR_FPCC; } } - return ret; + finish_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, retaddr); } static inline void float_zero_divide_excp(CPUPPCState *env, uintptr_t raddr) @@ -606,13 +638,6 @@ static void do_float_check_status(CPUPPCState *env, uintptr_t raddr) } } -static inline __attribute__((__always_inline__)) -void float_check_status(CPUPPCState *env) -{ - /* GETPC() works here because this is inline */ - do_float_check_status(env, GETPC()); -} - void helper_float_check_status(CPUPPCState *env) { do_float_check_status(env, GETPC()); @@ -623,6 +648,17 @@ void helper_reset_fpstatus(CPUPPCState *env) set_float_exception_flags(0, &env->fp_status); } +static void float_invalid_op_addsub(CPUPPCState *env, bool set_fpcc, + uintptr_t retaddr, int classes) +{ + if ((classes & ~is_neg) == is_inf) { + /* Magnitude subtraction of infinities */ + float_invalid_op_vxisi(env, set_fpcc, retaddr); + } else if (classes & is_snan) { + float_invalid_op_vxsnan(env, retaddr); + } +} + /* fadd - fadd. */ float64 helper_fadd(CPUPPCState *env, float64 arg1, float64 arg2) { @@ -630,14 +666,9 @@ float64 helper_fadd(CPUPPCState *env, float64 arg1, float64 arg2) int status = get_float_exception_flags(&env->fp_status); if (unlikely(status & float_flag_invalid)) { - if (float64_is_infinity(arg1) && float64_is_infinity(arg2)) { - /* Magnitude subtraction of infinities */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1); - } else if (float64_is_signaling_nan(arg1, &env->fp_status) || - float64_is_signaling_nan(arg2, &env->fp_status)) { - /* sNaN addition */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); - } + float_invalid_op_addsub(env, 1, GETPC(), + float64_classify(arg1) | + float64_classify(arg2)); } return ret; @@ -650,19 +681,25 @@ float64 helper_fsub(CPUPPCState *env, float64 arg1, float64 arg2) int status = get_float_exception_flags(&env->fp_status); if (unlikely(status & float_flag_invalid)) { - if (float64_is_infinity(arg1) && float64_is_infinity(arg2)) { - /* Magnitude subtraction of infinities */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1); - } else if (float64_is_signaling_nan(arg1, &env->fp_status) || - float64_is_signaling_nan(arg2, &env->fp_status)) { - /* sNaN addition */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); - } + float_invalid_op_addsub(env, 1, GETPC(), + float64_classify(arg1) | + float64_classify(arg2)); } return ret; } +static void float_invalid_op_mul(CPUPPCState *env, bool set_fprc, + uintptr_t retaddr, int classes) +{ + if ((classes & (is_zero | is_inf)) == (is_zero | is_inf)) { + /* Multiplication of zero by infinity */ + float_invalid_op_vximz(env, set_fprc, retaddr); + } else if (classes & is_snan) { + float_invalid_op_vxsnan(env, retaddr); + } +} + /* fmul - fmul. */ float64 helper_fmul(CPUPPCState *env, float64 arg1, float64 arg2) { @@ -670,20 +707,29 @@ float64 helper_fmul(CPUPPCState *env, float64 arg1, float64 arg2) int status = get_float_exception_flags(&env->fp_status); if (unlikely(status & float_flag_invalid)) { - if ((float64_is_infinity(arg1) && float64_is_zero(arg2)) || - (float64_is_zero(arg1) && float64_is_infinity(arg2))) { - /* Multiplication of zero by infinity */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1); - } else if (float64_is_signaling_nan(arg1, &env->fp_status) || - float64_is_signaling_nan(arg2, &env->fp_status)) { - /* sNaN multiplication */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); - } + float_invalid_op_mul(env, 1, GETPC(), + float64_classify(arg1) | + float64_classify(arg2)); } return ret; } +static void float_invalid_op_div(CPUPPCState *env, bool set_fprc, + uintptr_t retaddr, int classes) +{ + classes &= ~is_neg; + if (classes == is_inf) { + /* Division of infinity by infinity */ + float_invalid_op_vxidi(env, set_fprc, retaddr); + } else if (classes == is_zero) { + /* Division of zero by zero */ + float_invalid_op_vxzdz(env, set_fprc, retaddr); + } else if (classes & is_snan) { + float_invalid_op_vxsnan(env, retaddr); + } +} + /* fdiv - fdiv. */ float64 helper_fdiv(CPUPPCState *env, float64 arg1, float64 arg2) { @@ -692,18 +738,9 @@ float64 helper_fdiv(CPUPPCState *env, float64 arg1, float64 arg2) if (unlikely(status)) { if (status & float_flag_invalid) { - /* Determine what kind of invalid operation was seen. */ - if (float64_is_infinity(arg1) && float64_is_infinity(arg2)) { - /* Division of infinity by infinity */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, 1); - } else if (float64_is_zero(arg1) && float64_is_zero(arg2)) { - /* Division of zero by zero */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, 1); - } else if (float64_is_signaling_nan(arg1, &env->fp_status) || - float64_is_signaling_nan(arg2, &env->fp_status)) { - /* sNaN division */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); - } + float_invalid_op_div(env, 1, GETPC(), + float64_classify(arg1) | + float64_classify(arg2)); } if (status & float_flag_divbyzero) { float_zero_divide_excp(env, GETPC()); @@ -713,30 +750,30 @@ float64 helper_fdiv(CPUPPCState *env, float64 arg1, float64 arg2) return ret; } +static void float_invalid_cvt(CPUPPCState *env, bool set_fprc, + uintptr_t retaddr, int class1) +{ + float_invalid_op_vxcvi(env, set_fprc, retaddr); + if (class1 & is_snan) { + float_invalid_op_vxsnan(env, retaddr); + } +} #define FPU_FCTI(op, cvt, nanval) \ -uint64_t helper_##op(CPUPPCState *env, uint64_t arg) \ +uint64_t helper_##op(CPUPPCState *env, float64 arg) \ { \ - CPU_DoubleU farg; \ - \ - farg.ll = arg; \ - farg.ll = float64_to_##cvt(farg.d, &env->fp_status); \ + uint64_t ret = float64_to_##cvt(arg, &env->fp_status); \ + int status = get_float_exception_flags(&env->fp_status); \ \ - if (unlikely(env->fp_status.float_exception_flags)) { \ - if (float64_is_any_nan(arg)) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1); \ - if (float64_is_signaling_nan(arg, &env->fp_status)) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); \ - } \ - farg.ll = nanval; \ - } else if (env->fp_status.float_exception_flags & \ - float_flag_invalid) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1); \ + if (unlikely(status)) { \ + if (status & float_flag_invalid) { \ + float_invalid_cvt(env, 1, GETPC(), float64_classify(arg)); \ + ret = nanval; \ } \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } \ - return farg.ll; \ - } + return ret; \ +} FPU_FCTI(fctiw, int32, 0x80000000U) FPU_FCTI(fctiwz, int32_round_to_zero, 0x80000000U) @@ -758,7 +795,7 @@ uint64_t helper_##op(CPUPPCState *env, uint64_t arg) \ } else { \ farg.d = cvtr(arg, &env->fp_status); \ } \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ return farg.ll; \ } @@ -776,7 +813,7 @@ static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg, if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) { /* sNaN round */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + float_invalid_op_vxsnan(env, GETPC()); farg.ll = arg | 0x0008000000000000ULL; } else { int inexact = get_float_exception_flags(&env->fp_status) & @@ -791,7 +828,7 @@ static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg, env->fp_status.float_exception_flags &= ~float_flag_inexact; } } - float_check_status(env); + do_float_check_status(env, GETPC()); return farg.ll; } @@ -817,18 +854,18 @@ uint64_t helper_frim(CPUPPCState *env, uint64_t arg) #define FPU_MADDSUB_UPDATE(NAME, TP) \ static void NAME(CPUPPCState *env, TP arg1, TP arg2, TP arg3, \ - unsigned int madd_flags) \ + unsigned int madd_flags, uintptr_t retaddr) \ { \ if (TP##_is_signaling_nan(arg1, &env->fp_status) || \ TP##_is_signaling_nan(arg2, &env->fp_status) || \ TP##_is_signaling_nan(arg3, &env->fp_status)) { \ /* sNaN operation */ \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); \ + float_invalid_op_vxsnan(env, retaddr); \ } \ if ((TP##_is_infinity(arg1) && TP##_is_zero(arg2)) || \ (TP##_is_zero(arg1) && TP##_is_infinity(arg2))) { \ /* Multiplication of zero by infinity */ \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1); \ + float_invalid_op_vximz(env, 1, retaddr); \ } \ if ((TP##_is_infinity(arg1) || TP##_is_infinity(arg2)) && \ TP##_is_infinity(arg3)) { \ @@ -841,7 +878,7 @@ static void NAME(CPUPPCState *env, TP arg1, TP arg2, TP arg3, \ cSign ^= 1; \ } \ if (aSign ^ bSign ^ cSign) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1); \ + float_invalid_op_vxisi(env, 1, retaddr); \ } \ } \ } @@ -859,9 +896,9 @@ uint64_t helper_##op(CPUPPCState *env, uint64_t arg1, \ if (flags) { \ if (flags & float_flag_invalid) { \ float64_maddsub_update_excp(env, arg1, arg2, arg3, \ - madd_flags); \ + madd_flags, GETPC()); \ } \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } \ return ret; \ } @@ -885,8 +922,7 @@ uint64_t helper_frsp(CPUPPCState *env, uint64_t arg) farg.ll = arg; if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) { - /* sNaN square root */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + float_invalid_op_vxsnan(env, GETPC()); } f32 = float64_to_float32(farg.d, &env->fp_status); farg.d = float32_to_float64(f32, &env->fp_status); @@ -904,11 +940,11 @@ float64 helper_fsqrt(CPUPPCState *env, float64 arg) if (unlikely(float64_is_any_nan(arg))) { if (unlikely(float64_is_signaling_nan(arg, &env->fp_status))) { /* sNaN square root */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + float_invalid_op_vxsnan(env, GETPC()); } } else { /* Square root of a negative nonzero number */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1); + float_invalid_op_vxsqrt(env, 1, GETPC()); } } @@ -926,7 +962,7 @@ float64 helper_fre(CPUPPCState *env, float64 arg) if (status & float_flag_invalid) { if (float64_is_signaling_nan(arg, &env->fp_status)) { /* sNaN reciprocal */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + float_invalid_op_vxsnan(env, GETPC()); } } if (status & float_flag_divbyzero) { @@ -949,7 +985,7 @@ uint64_t helper_fres(CPUPPCState *env, uint64_t arg) if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) { /* sNaN reciprocal */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + float_invalid_op_vxsnan(env, GETPC()); } farg.d = float64_div(float64_one, farg.d, &env->fp_status); f32 = float64_to_float32(farg.d, &env->fp_status); @@ -970,10 +1006,10 @@ float64 helper_frsqrte(CPUPPCState *env, float64 arg) if (status & float_flag_invalid) { if (float64_is_signaling_nan(arg, &env->fp_status)) { /* sNaN reciprocal */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + float_invalid_op_vxsnan(env, GETPC()); } else { /* Square root of a negative nonzero number */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1); + float_invalid_op_vxsqrt(env, 1, GETPC()); } } if (status & float_flag_divbyzero) { @@ -1095,7 +1131,7 @@ void helper_fcmpu(CPUPPCState *env, uint64_t arg1, uint64_t arg2, && (float64_is_signaling_nan(farg1.d, &env->fp_status) || float64_is_signaling_nan(farg2.d, &env->fp_status)))) { /* sNaN comparison */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + float_invalid_op_vxsnan(env, GETPC()); } } @@ -1123,14 +1159,11 @@ void helper_fcmpo(CPUPPCState *env, uint64_t arg1, uint64_t arg2, env->fpscr |= ret << FPSCR_FPRF; env->crf[crfD] = ret; if (unlikely(ret == 0x01UL)) { + float_invalid_op_vxvc(env, 1, GETPC()); if (float64_is_signaling_nan(farg1.d, &env->fp_status) || float64_is_signaling_nan(farg2.d, &env->fp_status)) { /* sNaN comparison */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN | - POWERPC_EXCP_FP_VXVC, 1); - } else { - /* qNaN comparison */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 1); + float_invalid_op_vxsnan(env, GETPC()); } } } @@ -1782,12 +1815,9 @@ void helper_##name(CPUPPCState *env, uint32_t opcode) \ env->fp_status.float_exception_flags |= tstat.float_exception_flags; \ \ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ - if (tp##_is_infinity(xa.fld) && tp##_is_infinity(xb.fld)) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf); \ - } else if (tp##_is_signaling_nan(xa.fld, &tstat) || \ - tp##_is_signaling_nan(xb.fld, &tstat)) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ - } \ + float_invalid_op_addsub(env, sfprf, GETPC(), \ + tp##_classify(xa.fld) | \ + tp##_classify(xb.fld)); \ } \ \ if (r2sp) { \ @@ -1799,7 +1829,7 @@ void helper_##name(CPUPPCState *env, uint32_t opcode) \ } \ } \ putVSR(xT(opcode), &xt, env); \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_ADD_SUB(xsadddp, add, 1, float64, VsrD(0), 1, 0) @@ -1831,18 +1861,15 @@ void helper_xsaddqp(CPUPPCState *env, uint32_t opcode) env->fp_status.float_exception_flags |= tstat.float_exception_flags; if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { - if (float128_is_infinity(xa.f128) && float128_is_infinity(xb.f128)) { - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1); - } else if (float128_is_signaling_nan(xa.f128, &tstat) || - float128_is_signaling_nan(xb.f128, &tstat)) { - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); - } + float_invalid_op_addsub(env, 1, GETPC(), + float128_classify(xa.f128) | + float128_classify(xb.f128)); } helper_compute_fprf_float128(env, xt.f128); putVSR(rD(opcode) + 32, &xt, env); - float_check_status(env); + do_float_check_status(env, GETPC()); } /* VSX_MUL - VSX floating point multiply @@ -1870,13 +1897,9 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ env->fp_status.float_exception_flags |= tstat.float_exception_flags; \ \ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ - if ((tp##_is_infinity(xa.fld) && tp##_is_zero(xb.fld)) || \ - (tp##_is_infinity(xb.fld) && tp##_is_zero(xa.fld))) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, sfprf); \ - } else if (tp##_is_signaling_nan(xa.fld, &tstat) || \ - tp##_is_signaling_nan(xb.fld, &tstat)) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ - } \ + float_invalid_op_mul(env, sfprf, GETPC(), \ + tp##_classify(xa.fld) | \ + tp##_classify(xb.fld)); \ } \ \ if (r2sp) { \ @@ -1889,7 +1912,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ putVSR(xT(opcode), &xt, env); \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_MUL(xsmuldp, 1, float64, VsrD(0), 1, 0) @@ -1917,18 +1940,14 @@ void helper_xsmulqp(CPUPPCState *env, uint32_t opcode) env->fp_status.float_exception_flags |= tstat.float_exception_flags; if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { - if ((float128_is_infinity(xa.f128) && float128_is_zero(xb.f128)) || - (float128_is_infinity(xb.f128) && float128_is_zero(xa.f128))) { - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1); - } else if (float128_is_signaling_nan(xa.f128, &tstat) || - float128_is_signaling_nan(xb.f128, &tstat)) { - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); - } + float_invalid_op_mul(env, 1, GETPC(), + float128_classify(xa.f128) | + float128_classify(xb.f128)); } helper_compute_fprf_float128(env, xt.f128); putVSR(rD(opcode) + 32, &xt, env); - float_check_status(env); + do_float_check_status(env, GETPC()); } /* VSX_DIV - VSX floating point divide @@ -1956,15 +1975,9 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ env->fp_status.float_exception_flags |= tstat.float_exception_flags; \ \ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ - if (tp##_is_infinity(xa.fld) && tp##_is_infinity(xb.fld)) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, sfprf); \ - } else if (tp##_is_zero(xa.fld) && \ - tp##_is_zero(xb.fld)) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, sfprf); \ - } else if (tp##_is_signaling_nan(xa.fld, &tstat) || \ - tp##_is_signaling_nan(xb.fld, &tstat)) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ - } \ + float_invalid_op_div(env, sfprf, GETPC(), \ + tp##_classify(xa.fld) | \ + tp##_classify(xb.fld)); \ } \ if (unlikely(tstat.float_exception_flags & float_flag_divbyzero)) { \ float_zero_divide_excp(env, GETPC()); \ @@ -1980,7 +1993,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ putVSR(xT(opcode), &xt, env); \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_DIV(xsdivdp, 1, float64, VsrD(0), 1, 0) @@ -2008,15 +2021,9 @@ void helper_xsdivqp(CPUPPCState *env, uint32_t opcode) env->fp_status.float_exception_flags |= tstat.float_exception_flags; if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { - if (float128_is_infinity(xa.f128) && float128_is_infinity(xb.f128)) { - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, 1); - } else if (float128_is_zero(xa.f128) && - float128_is_zero(xb.f128)) { - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, 1); - } else if (float128_is_signaling_nan(xa.f128, &tstat) || - float128_is_signaling_nan(xb.f128, &tstat)) { - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); - } + float_invalid_op_div(env, 1, GETPC(), + float128_classify(xa.f128) | + float128_classify(xb.f128)); } if (unlikely(tstat.float_exception_flags & float_flag_divbyzero)) { float_zero_divide_excp(env, GETPC()); @@ -2024,7 +2031,7 @@ void helper_xsdivqp(CPUPPCState *env, uint32_t opcode) helper_compute_fprf_float128(env, xt.f128); putVSR(rD(opcode) + 32, &xt, env); - float_check_status(env); + do_float_check_status(env, GETPC()); } /* VSX_RE - VSX floating point reciprocal estimate @@ -2046,7 +2053,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ \ for (i = 0; i < nels; i++) { \ if (unlikely(tp##_is_signaling_nan(xb.fld, &env->fp_status))) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ + float_invalid_op_vxsnan(env, GETPC()); \ } \ xt.fld = tp##_div(tp##_one, xb.fld, &env->fp_status); \ \ @@ -2060,7 +2067,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ putVSR(xT(opcode), &xt, env); \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_RE(xsredp, 1, float64, VsrD(0), 1, 0) @@ -2093,9 +2100,9 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ \ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ if (tp##_is_neg(xb.fld) && !tp##_is_zero(xb.fld)) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf); \ + float_invalid_op_vxsqrt(env, sfprf, GETPC()); \ } else if (tp##_is_signaling_nan(xb.fld, &tstat)) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ + float_invalid_op_vxsnan(env, GETPC()); \ } \ } \ \ @@ -2109,7 +2116,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ putVSR(xT(opcode), &xt, env); \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_SQRT(xssqrtdp, 1, float64, VsrD(0), 1, 0) @@ -2143,9 +2150,9 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ \ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ if (tp##_is_neg(xb.fld) && !tp##_is_zero(xb.fld)) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf); \ + float_invalid_op_vxsqrt(env, sfprf, GETPC()); \ } else if (tp##_is_signaling_nan(xb.fld, &tstat)) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ + float_invalid_op_vxsnan(env, GETPC()); \ } \ } \ \ @@ -2159,7 +2166,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ putVSR(xT(opcode), &xt, env); \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_RSQRTE(xsrsqrtedp, 1, float64, VsrD(0), 1, 0) @@ -2329,7 +2336,8 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ env->fp_status.float_exception_flags |= tstat.float_exception_flags; \ \ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ - tp##_maddsub_update_excp(env, xa.fld, b->fld, c->fld, maddflgs); \ + tp##_maddsub_update_excp(env, xa.fld, b->fld, \ + c->fld, maddflgs, GETPC()); \ } \ \ if (r2sp) { \ @@ -2341,7 +2349,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ } \ putVSR(xT(opcode), &xt_out, env); \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_MADD(xsmaddadp, 1, float64, VsrD(0), MADD_FLGS, 1, 1, 0) @@ -2407,10 +2415,10 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ float64_is_quiet_nan(xb.VsrD(0), &env->fp_status); \ } \ if (vxsnan_flag) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ + float_invalid_op_vxsnan(env, GETPC()); \ } \ if (vxvc_flag) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0); \ + float_invalid_op_vxvc(env, 0, GETPC()); \ } \ vex_flag = fpscr_ve && (vxvc_flag || vxsnan_flag); \ \ @@ -2424,7 +2432,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ } \ putVSR(xT(opcode), &xt, env); \ - helper_float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_SCALAR_CMP_DP(xscmpeqdp, eq, 1, 0) @@ -2461,7 +2469,7 @@ void helper_xscmpexpdp(CPUPPCState *env, uint32_t opcode) env->fpscr |= cc << FPSCR_FPRF; env->crf[BF(opcode)] = cc; - helper_float_check_status(env); + do_float_check_status(env, GETPC()); } void helper_xscmpexpqp(CPUPPCState *env, uint32_t opcode) @@ -2493,7 +2501,7 @@ void helper_xscmpexpqp(CPUPPCState *env, uint32_t opcode) env->fpscr |= cc << FPSCR_FPRF; env->crf[BF(opcode)] = cc; - helper_float_check_status(env); + do_float_check_status(env, GETPC()); } #define VSX_SCALAR_CMP(op, ordered) \ @@ -2522,10 +2530,10 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ } \ if (vxsnan_flag) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ + float_invalid_op_vxsnan(env, GETPC()); \ } \ if (vxvc_flag) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0); \ + float_invalid_op_vxvc(env, 0, GETPC()); \ } \ \ if (float64_lt(xa.VsrD(0), xb.VsrD(0), &env->fp_status)) { \ @@ -2540,7 +2548,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ env->fpscr |= cc << FPSCR_FPRF; \ env->crf[BF(opcode)] = cc; \ \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_SCALAR_CMP(xscmpodp, 1) @@ -2572,10 +2580,10 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ } \ if (vxsnan_flag) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ + float_invalid_op_vxsnan(env, GETPC()); \ } \ if (vxvc_flag) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0); \ + float_invalid_op_vxvc(env, 0, GETPC()); \ } \ \ if (float128_lt(xa.f128, xb.f128, &env->fp_status)) { \ @@ -2590,7 +2598,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ env->fpscr |= cc << FPSCR_FPRF; \ env->crf[BF(opcode)] = cc; \ \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_SCALAR_CMPQ(xscmpoqp, 1) @@ -2617,12 +2625,12 @@ void helper_##name(CPUPPCState *env, uint32_t opcode) \ xt.fld = tp##_##op(xa.fld, xb.fld, &env->fp_status); \ if (unlikely(tp##_is_signaling_nan(xa.fld, &env->fp_status) || \ tp##_is_signaling_nan(xb.fld, &env->fp_status))) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ + float_invalid_op_vxsnan(env, GETPC()); \ } \ } \ \ putVSR(xT(opcode), &xt, env); \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_MAX_MIN(xsmaxdp, maxnum, 1, float64, VsrD(0)) @@ -2660,7 +2668,7 @@ void helper_##name(CPUPPCState *env, uint32_t opcode) \ \ vex_flag = fpscr_ve & vxsnan_flag; \ if (vxsnan_flag) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ + float_invalid_op_vxsnan(env, GETPC()); \ } \ if (!vex_flag) { \ putVSR(rD(opcode) + 32, &xt, env); \ @@ -2715,7 +2723,7 @@ void helper_##name(CPUPPCState *env, uint32_t opcode) \ \ vex_flag = fpscr_ve & vxsnan_flag; \ if (vxsnan_flag) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ + float_invalid_op_vxsnan(env, GETPC()); \ } \ if (!vex_flag) { \ putVSR(rD(opcode) + 32, &xt, env); \ @@ -2751,10 +2759,10 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ tp##_is_any_nan(xb.fld))) { \ if (tp##_is_signaling_nan(xa.fld, &env->fp_status) || \ tp##_is_signaling_nan(xb.fld, &env->fp_status)) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ + float_invalid_op_vxsnan(env, GETPC()); \ } \ if (svxvc) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0); \ + float_invalid_op_vxvc(env, 0, GETPC()); \ } \ xt.fld = 0; \ all_true = 0; \ @@ -2773,7 +2781,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ if ((opcode >> (31-21)) & 1) { \ env->crf[6] = (all_true ? 0x8 : 0) | (all_false ? 0x2 : 0); \ } \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_CMP(xvcmpeqdp, 2, float64, VsrD(i), eq, 0, 1) @@ -2807,7 +2815,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ xt.tfld = stp##_to_##ttp(xb.sfld, &env->fp_status); \ if (unlikely(stp##_is_signaling_nan(xb.sfld, \ &env->fp_status))) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ + float_invalid_op_vxsnan(env, GETPC()); \ xt.tfld = ttp##_snan_to_qnan(xt.tfld); \ } \ if (sfprf) { \ @@ -2816,7 +2824,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ putVSR(xT(opcode), &xt, env); \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_CVT_FP_TO_FP(xscvdpsp, 1, float64, float32, VsrD(0), VsrW(0), 1) @@ -2846,7 +2854,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ xt.tfld = stp##_to_##ttp(xb.sfld, &env->fp_status); \ if (unlikely(stp##_is_signaling_nan(xb.sfld, \ &env->fp_status))) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ + float_invalid_op_vxsnan(env, GETPC()); \ xt.tfld = ttp##_snan_to_qnan(xt.tfld); \ } \ if (sfprf) { \ @@ -2855,7 +2863,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ putVSR(rD(opcode) + 32, &xt, env); \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_CVT_FP_TO_FP_VECTOR(xscvdpqp, 1, float64, float128, VsrD(0), f128, 1) @@ -2883,7 +2891,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ xt.tfld = stp##_to_##ttp(xb.sfld, 1, &env->fp_status); \ if (unlikely(stp##_is_signaling_nan(xb.sfld, \ &env->fp_status))) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ + float_invalid_op_vxsnan(env, GETPC()); \ xt.tfld = ttp##_snan_to_qnan(xt.tfld); \ } \ if (sfprf) { \ @@ -2892,7 +2900,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ putVSR(xT(opcode), &xt, env); \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_CVT_FP_TO_FP_HP(xscvdphp, 1, float64, float16, VsrD(0), VsrH(3), 1) @@ -2919,15 +2927,14 @@ void helper_xscvqpdp(CPUPPCState *env, uint32_t opcode) xt.VsrD(0) = float128_to_float64(xb.f128, &tstat); env->fp_status.float_exception_flags |= tstat.float_exception_flags; - if (unlikely(float128_is_signaling_nan(xb.f128, - &tstat))) { - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); + if (unlikely(float128_is_signaling_nan(xb.f128, &tstat))) { + float_invalid_op_vxsnan(env, GETPC()); xt.VsrD(0) = float64_snan_to_qnan(xt.VsrD(0)); } helper_compute_fprf_float64(env, xt.VsrD(0)); putVSR(rD(opcode) + 32, &xt, env); - float_check_status(env); + do_float_check_status(env, GETPC()); } uint64_t helper_xscvdpspn(CPUPPCState *env, uint64_t xb) @@ -2958,6 +2965,7 @@ uint64_t helper_xscvspdpn(CPUPPCState *env, uint64_t xb) #define VSX_CVT_FP_TO_INT(op, nels, stp, ttp, sfld, tfld, rnan) \ void helper_##op(CPUPPCState *env, uint32_t opcode) \ { \ + int all_flags = env->fp_status.float_exception_flags, flags; \ ppc_vsr_t xt, xb; \ int i; \ \ @@ -2965,23 +2973,19 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ getVSR(xT(opcode), &xt, env); \ \ for (i = 0; i < nels; i++) { \ - if (unlikely(stp##_is_any_nan(xb.sfld))) { \ - if (stp##_is_signaling_nan(xb.sfld, &env->fp_status)) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ - } \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0); \ + env->fp_status.float_exception_flags = 0; \ + xt.tfld = stp##_to_##ttp##_round_to_zero(xb.sfld, &env->fp_status); \ + flags = env->fp_status.float_exception_flags; \ + if (unlikely(flags & float_flag_invalid)) { \ + float_invalid_cvt(env, 0, GETPC(), stp##_classify(xb.sfld)); \ xt.tfld = rnan; \ - } else { \ - xt.tfld = stp##_to_##ttp##_round_to_zero(xb.sfld, \ - &env->fp_status); \ - if (env->fp_status.float_exception_flags & float_flag_invalid) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0); \ - } \ } \ + all_flags |= flags; \ } \ \ putVSR(xT(opcode), &xt, env); \ - float_check_status(env); \ + env->fp_status.float_exception_flags = all_flags; \ + do_float_check_status(env, GETPC()); \ } VSX_CVT_FP_TO_INT(xscvdpsxds, 1, float64, int64, VsrD(0), VsrD(0), \ @@ -3018,22 +3022,14 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ getVSR(rB(opcode) + 32, &xb, env); \ memset(&xt, 0, sizeof(xt)); \ \ - if (unlikely(stp##_is_any_nan(xb.sfld))) { \ - if (stp##_is_signaling_nan(xb.sfld, &env->fp_status)) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ - } \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0); \ + xt.tfld = stp##_to_##ttp##_round_to_zero(xb.sfld, &env->fp_status); \ + if (env->fp_status.float_exception_flags & float_flag_invalid) { \ + float_invalid_cvt(env, 0, GETPC(), stp##_classify(xb.sfld)); \ xt.tfld = rnan; \ - } else { \ - xt.tfld = stp##_to_##ttp##_round_to_zero(xb.sfld, \ - &env->fp_status); \ - if (env->fp_status.float_exception_flags & float_flag_invalid) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0); \ - } \ } \ \ putVSR(rD(opcode) + 32, &xt, env); \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_CVT_FP_TO_INT_VECTOR(xscvqpsdz, float128, int64, f128, VsrD(0), \ @@ -3074,7 +3070,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ putVSR(xT(opcode), &xt, env); \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_CVT_INT_TO_FP(xscvsxddp, 1, int64, float64, VsrD(0), VsrD(0), 1, 0) @@ -3109,7 +3105,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ helper_compute_fprf_##ttp(env, xt.tfld); \ \ putVSR(xT(opcode) + 32, &xt, env); \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_CVT_INT_TO_FP_VECTOR(xscvsdqp, int64, float128, VsrD(0), f128) @@ -3144,7 +3140,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ for (i = 0; i < nels; i++) { \ if (unlikely(tp##_is_signaling_nan(xb.fld, \ &env->fp_status))) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ + float_invalid_op_vxsnan(env, GETPC()); \ xt.fld = tp##_snan_to_qnan(xb.fld); \ } else { \ xt.fld = tp##_round_to_int(xb.fld, &env->fp_status); \ @@ -3163,7 +3159,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ putVSR(xT(opcode), &xt, env); \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_ROUND(xsrdpi, 1, float64, VsrD(0), float_round_ties_away, 1) @@ -3191,7 +3187,7 @@ uint64_t helper_xsrsp(CPUPPCState *env, uint64_t xb) uint64_t xt = helper_frsp(env, xb); helper_compute_fprf_float64(env, xt); - float_check_status(env); + do_float_check_status(env, GETPC()); return xt; } @@ -3373,7 +3369,7 @@ void helper_xsrqpi(CPUPPCState *env, uint32_t opcode) if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { if (float128_is_signaling_nan(xb.f128, &tstat)) { - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); + float_invalid_op_vxsnan(env, GETPC()); xt.f128 = float128_snan_to_qnan(xt.f128); } } @@ -3383,7 +3379,7 @@ void helper_xsrqpi(CPUPPCState *env, uint32_t opcode) } helper_compute_fprf_float128(env, xt.f128); - float_check_status(env); + do_float_check_status(env, GETPC()); putVSR(rD(opcode) + 32, &xt, env); } @@ -3433,14 +3429,14 @@ void helper_xsrqpxp(CPUPPCState *env, uint32_t opcode) if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { if (float128_is_signaling_nan(xb.f128, &tstat)) { - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); + float_invalid_op_vxsnan(env, GETPC()); xt.f128 = float128_snan_to_qnan(xt.f128); } } helper_compute_fprf_float128(env, xt.f128); putVSR(rD(opcode) + 32, &xt, env); - float_check_status(env); + do_float_check_status(env, GETPC()); } void helper_xssqrtqp(CPUPPCState *env, uint32_t opcode) @@ -3464,19 +3460,19 @@ void helper_xssqrtqp(CPUPPCState *env, uint32_t opcode) if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { if (float128_is_signaling_nan(xb.f128, &tstat)) { - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + float_invalid_op_vxsnan(env, GETPC()); xt.f128 = float128_snan_to_qnan(xb.f128); } else if (float128_is_quiet_nan(xb.f128, &tstat)) { xt.f128 = xb.f128; } else if (float128_is_neg(xb.f128) && !float128_is_zero(xb.f128)) { - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1); + float_invalid_op_vxsqrt(env, 1, GETPC()); xt.f128 = float128_default_nan(&env->fp_status); } } helper_compute_fprf_float128(env, xt.f128); putVSR(rD(opcode) + 32, &xt, env); - float_check_status(env); + do_float_check_status(env, GETPC()); } void helper_xssubqp(CPUPPCState *env, uint32_t opcode) @@ -3499,15 +3495,12 @@ void helper_xssubqp(CPUPPCState *env, uint32_t opcode) env->fp_status.float_exception_flags |= tstat.float_exception_flags; if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { - if (float128_is_infinity(xa.f128) && float128_is_infinity(xb.f128)) { - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1); - } else if (float128_is_signaling_nan(xa.f128, &tstat) || - float128_is_signaling_nan(xb.f128, &tstat)) { - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); - } + float_invalid_op_addsub(env, 1, GETPC(), + float128_classify(xa.f128) | + float128_classify(xb.f128)); } helper_compute_fprf_float128(env, xt.f128); putVSR(rD(opcode) + 32, &xt, env); - float_check_status(env); + do_float_check_status(env, GETPC()); } diff --git a/target/ppc/helper.h b/target/ppc/helper.h index 7a1481fd0b..c7de04e068 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -29,7 +29,9 @@ DEF_HELPER_4(lsw, void, env, tl, i32, i32) DEF_HELPER_5(lswx, void, env, tl, i32, i32, i32) DEF_HELPER_FLAGS_4(stsw, TCG_CALL_NO_WG, void, env, tl, i32, i32) DEF_HELPER_FLAGS_3(dcbz, TCG_CALL_NO_WG, void, env, tl, i32) +DEF_HELPER_FLAGS_3(dcbzep, TCG_CALL_NO_WG, void, env, tl, i32) DEF_HELPER_FLAGS_2(icbi, TCG_CALL_NO_WG, void, env, tl) +DEF_HELPER_FLAGS_2(icbiep, TCG_CALL_NO_WG, void, env, tl) DEF_HELPER_5(lscbx, tl, env, tl, i32, i32, i32) #if defined(TARGET_PPC64) @@ -658,6 +660,8 @@ DEF_HELPER_2(booke206_tlbilx1, void, env, tl) DEF_HELPER_2(booke206_tlbilx3, void, env, tl) DEF_HELPER_2(booke206_tlbflush, void, env, tl) DEF_HELPER_3(booke_setpid, void, env, i32, tl) +DEF_HELPER_2(booke_set_eplc, void, env, tl) +DEF_HELPER_2(booke_set_epsc, void, env, tl) DEF_HELPER_2(6xx_tlbd, void, env, tl) DEF_HELPER_2(6xx_tlbi, void, env, tl) DEF_HELPER_2(74xx_tlbd, void, env, tl) diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index 30aeafa7de..f81327d6cd 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -91,6 +91,7 @@ static int cap_ppc_pvr_compat; static int cap_ppc_safe_cache; static int cap_ppc_safe_bounds_check; static int cap_ppc_safe_indirect_branch; +static int cap_ppc_nested_kvm_hv; static uint32_t debug_inst_opcode; @@ -150,6 +151,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s) cap_mmu_hash_v3 = kvm_vm_check_extension(s, KVM_CAP_PPC_MMU_HASH_V3); cap_resize_hpt = kvm_vm_check_extension(s, KVM_CAP_SPAPR_RESIZE_HPT); kvmppc_get_cpu_characteristics(s); + cap_ppc_nested_kvm_hv = kvm_vm_check_extension(s, KVM_CAP_PPC_NESTED_HV); /* * Note: setting it to false because there is not such capability * in KVM at this moment. @@ -2422,6 +2424,16 @@ int kvmppc_get_cap_safe_indirect_branch(void) return cap_ppc_safe_indirect_branch; } +bool kvmppc_has_cap_nested_kvm_hv(void) +{ + return !!cap_ppc_nested_kvm_hv; +} + +int kvmppc_set_cap_nested_kvm_hv(int enable) +{ + return kvm_vm_enable_cap(kvm_state, KVM_CAP_PPC_NESTED_HV, 0, enable); +} + bool kvmppc_has_cap_spapr_vfio(void) { return cap_spapr_vfio; diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h index f696c6e498..bdfaa4e70a 100644 --- a/target/ppc/kvm_ppc.h +++ b/target/ppc/kvm_ppc.h @@ -62,6 +62,8 @@ bool kvmppc_has_cap_mmu_hash_v3(void); int kvmppc_get_cap_safe_cache(void); int kvmppc_get_cap_safe_bounds_check(void); int kvmppc_get_cap_safe_indirect_branch(void); +bool kvmppc_has_cap_nested_kvm_hv(void); +int kvmppc_set_cap_nested_kvm_hv(int enable); int kvmppc_enable_hwrng(void); int kvmppc_put_books_sregs(PowerPCCPU *cpu); PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void); @@ -320,6 +322,16 @@ static inline int kvmppc_get_cap_safe_indirect_branch(void) return 0; } +static inline bool kvmppc_has_cap_nested_kvm_hv(void) +{ + return false; +} + +static inline int kvmppc_set_cap_nested_kvm_hv(int enable) +{ + return -1; +} + static inline int kvmppc_enable_hwrng(void) { return -1; diff --git a/target/ppc/mem_helper.c b/target/ppc/mem_helper.c index a1485fad9b..9c5a68579e 100644 --- a/target/ppc/mem_helper.c +++ b/target/ppc/mem_helper.c @@ -142,11 +142,13 @@ void helper_stsw(CPUPPCState *env, target_ulong addr, uint32_t nb, } } -void helper_dcbz(CPUPPCState *env, target_ulong addr, uint32_t opcode) +static void dcbz_common(CPUPPCState *env, target_ulong addr, + uint32_t opcode, bool epid, uintptr_t retaddr) { target_ulong mask, dcbz_size = env->dcache_line_size; uint32_t i; void *haddr; + int mmu_idx = epid ? PPC_TLB_EPID_STORE : env->dmmu_idx; #if defined(TARGET_PPC64) /* Check for dcbz vs dcbzl on 970 */ @@ -166,17 +168,34 @@ void helper_dcbz(CPUPPCState *env, target_ulong addr, uint32_t opcode) } /* Try fast path translate */ - haddr = tlb_vaddr_to_host(env, addr, MMU_DATA_STORE, env->dmmu_idx); + haddr = tlb_vaddr_to_host(env, addr, MMU_DATA_STORE, mmu_idx); if (haddr) { memset(haddr, 0, dcbz_size); } else { /* Slow path */ for (i = 0; i < dcbz_size; i += 8) { - cpu_stq_data_ra(env, addr + i, 0, GETPC()); + if (epid) { +#if !defined(CONFIG_USER_ONLY) + /* Does not make sense on USER_ONLY config */ + cpu_stq_eps_ra(env, addr + i, 0, retaddr); +#endif + } else { + cpu_stq_data_ra(env, addr + i, 0, retaddr); + } } } } +void helper_dcbz(CPUPPCState *env, target_ulong addr, uint32_t opcode) +{ + dcbz_common(env, addr, opcode, false, GETPC()); +} + +void helper_dcbzep(CPUPPCState *env, target_ulong addr, uint32_t opcode) +{ + dcbz_common(env, addr, opcode, true, GETPC()); +} + void helper_icbi(CPUPPCState *env, target_ulong addr) { addr &= ~(env->dcache_line_size - 1); @@ -188,6 +207,15 @@ void helper_icbi(CPUPPCState *env, target_ulong addr) cpu_ldl_data_ra(env, addr, GETPC()); } +void helper_icbiep(CPUPPCState *env, target_ulong addr) +{ +#if !defined(CONFIG_USER_ONLY) + /* See comments above */ + addr &= ~(env->dcache_line_size - 1); + cpu_ldl_epl_ra(env, addr, GETPC()); +#endif +} + /* XXX: to be tested */ target_ulong helper_lscbx(CPUPPCState *env, target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb) diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c index 04f8317ea1..cefed34da4 100644 --- a/target/ppc/mmu_helper.c +++ b/target/ppc/mmu_helper.c @@ -924,29 +924,84 @@ static int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb, return 0; } +static bool is_epid_mmu(int mmu_idx) +{ + return mmu_idx == PPC_TLB_EPID_STORE || mmu_idx == PPC_TLB_EPID_LOAD; +} + +static uint32_t mmubooke206_esr(int mmu_idx, bool rw) +{ + uint32_t esr = 0; + if (rw) { + esr |= ESR_ST; + } + if (is_epid_mmu(mmu_idx)) { + esr |= ESR_EPID; + } + return esr; +} + +/* Get EPID register given the mmu_idx. If this is regular load, + * construct the EPID access bits from current processor state */ + +/* Get the effective AS and PR bits and the PID. The PID is returned only if + * EPID load is requested, otherwise the caller must detect the correct EPID. + * Return true if valid EPID is returned. */ +static bool mmubooke206_get_as(CPUPPCState *env, + int mmu_idx, uint32_t *epid_out, + bool *as_out, bool *pr_out) +{ + if (is_epid_mmu(mmu_idx)) { + uint32_t epidr; + if (mmu_idx == PPC_TLB_EPID_STORE) { + epidr = env->spr[SPR_BOOKE_EPSC]; + } else { + epidr = env->spr[SPR_BOOKE_EPLC]; + } + *epid_out = (epidr & EPID_EPID) >> EPID_EPID_SHIFT; + *as_out = !!(epidr & EPID_EAS); + *pr_out = !!(epidr & EPID_EPR); + return true; + } else { + *as_out = msr_ds; + *pr_out = msr_pr; + return false; + } +} + +/* Check if the tlb found by hashing really matches */ static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb, hwaddr *raddr, int *prot, target_ulong address, int rw, - int access_type) + int access_type, int mmu_idx) { int ret; int prot2 = 0; + uint32_t epid; + bool as, pr; + bool use_epid = mmubooke206_get_as(env, mmu_idx, &epid, &as, &pr); - if (ppcmas_tlb_check(env, tlb, raddr, address, - env->spr[SPR_BOOKE_PID]) >= 0) { - goto found_tlb; - } + if (!use_epid) { + if (ppcmas_tlb_check(env, tlb, raddr, address, + env->spr[SPR_BOOKE_PID]) >= 0) { + goto found_tlb; + } - if (env->spr[SPR_BOOKE_PID1] && - ppcmas_tlb_check(env, tlb, raddr, address, - env->spr[SPR_BOOKE_PID1]) >= 0) { - goto found_tlb; - } + if (env->spr[SPR_BOOKE_PID1] && + ppcmas_tlb_check(env, tlb, raddr, address, + env->spr[SPR_BOOKE_PID1]) >= 0) { + goto found_tlb; + } - if (env->spr[SPR_BOOKE_PID2] && - ppcmas_tlb_check(env, tlb, raddr, address, - env->spr[SPR_BOOKE_PID2]) >= 0) { - goto found_tlb; + if (env->spr[SPR_BOOKE_PID2] && + ppcmas_tlb_check(env, tlb, raddr, address, + env->spr[SPR_BOOKE_PID2]) >= 0) { + goto found_tlb; + } + } else { + if (ppcmas_tlb_check(env, tlb, raddr, address, epid) >= 0) { + goto found_tlb; + } } LOG_SWTLB("%s: TLB entry not found\n", __func__); @@ -954,7 +1009,7 @@ static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb, found_tlb: - if (msr_pr != 0) { + if (pr) { if (tlb->mas7_3 & MAS3_UR) { prot2 |= PAGE_READ; } @@ -978,6 +1033,8 @@ found_tlb: /* Check the address space and permissions */ if (access_type == ACCESS_CODE) { + /* There is no way to fetch code using epid load */ + assert(!use_epid); if (msr_ir != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) { LOG_SWTLB("%s: AS doesn't match\n", __func__); return -1; @@ -992,7 +1049,7 @@ found_tlb: LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2); ret = -3; } else { - if (msr_dr != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) { + if (as != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) { LOG_SWTLB("%s: AS doesn't match\n", __func__); return -1; } @@ -1012,7 +1069,7 @@ found_tlb: static int mmubooke206_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, target_ulong address, int rw, - int access_type) + int access_type, int mmu_idx) { ppcmas_tlb_t *tlb; hwaddr raddr; @@ -1030,7 +1087,7 @@ static int mmubooke206_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, continue; } ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address, - rw, access_type); + rw, access_type, mmu_idx); if (ret != -1) { goto found_tlb; } @@ -1348,8 +1405,10 @@ static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx, return ret; } -static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, - target_ulong eaddr, int rw, int access_type) +static int get_physical_address_wtlb( + CPUPPCState *env, mmu_ctx_t *ctx, + target_ulong eaddr, int rw, int access_type, + int mmu_idx) { PowerPCCPU *cpu = ppc_env_get_cpu(env); int ret = -1; @@ -1392,7 +1451,7 @@ static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, break; case POWERPC_MMU_BOOKE206: ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw, - access_type); + access_type, mmu_idx); break; case POWERPC_MMU_MPC8xx: /* XXX: TODO */ @@ -1417,6 +1476,13 @@ static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, return ret; } +static int get_physical_address( + CPUPPCState *env, mmu_ctx_t *ctx, + target_ulong eaddr, int rw, int access_type) +{ + return get_physical_address_wtlb(env, ctx, eaddr, rw, access_type, 0); +} + hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) { PowerPCCPU *cpu = POWERPC_CPU(cs); @@ -1463,8 +1529,15 @@ hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) } static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address, - int rw) + int rw, int mmu_idx) { + uint32_t epid; + bool as, pr; + uint32_t missed_tid = 0; + bool use_epid = mmubooke206_get_as(env, mmu_idx, &epid, &as, &pr); + if (rw == 2) { + as = msr_ir; + } env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK; env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK; env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK; @@ -1473,7 +1546,7 @@ static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address, env->spr[SPR_BOOKE_MAS7] = 0; /* AS */ - if (((rw == 2) && msr_ir) || ((rw != 2) && msr_dr)) { + if (as) { env->spr[SPR_BOOKE_MAS1] |= MAS1_TS; env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS; } @@ -1481,19 +1554,25 @@ static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address, env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID; env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK; - switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) { - case MAS4_TIDSELD_PID0: - env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID] << MAS1_TID_SHIFT; - break; - case MAS4_TIDSELD_PID1: - env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID1] << MAS1_TID_SHIFT; - break; - case MAS4_TIDSELD_PID2: - env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID2] << MAS1_TID_SHIFT; - break; + if (!use_epid) { + switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) { + case MAS4_TIDSELD_PID0: + missed_tid = env->spr[SPR_BOOKE_PID]; + break; + case MAS4_TIDSELD_PID1: + missed_tid = env->spr[SPR_BOOKE_PID1]; + break; + case MAS4_TIDSELD_PID2: + missed_tid = env->spr[SPR_BOOKE_PID2]; + break; + } + env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16; + } else { + missed_tid = epid; + env->spr[SPR_BOOKE_MAS6] |= missed_tid << 16; } + env->spr[SPR_BOOKE_MAS1] |= (missed_tid << MAS1_TID_SHIFT); - env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16; /* next victim logic */ env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT; @@ -1520,7 +1599,8 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, /* data access */ access_type = env->access_type; } - ret = get_physical_address(env, &ctx, address, rw, access_type); + ret = get_physical_address_wtlb(env, &ctx, address, rw, + access_type, mmu_idx); if (ret == 0) { tlb_set_page(cs, address & TARGET_PAGE_MASK, ctx.raddr & TARGET_PAGE_MASK, ctx.prot, @@ -1550,12 +1630,13 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, env->spr[SPR_40x_ESR] = 0x00000000; break; case POWERPC_MMU_BOOKE206: - booke206_update_mas_tlb_miss(env, address, 2); + booke206_update_mas_tlb_miss(env, address, 2, mmu_idx); /* fall through */ case POWERPC_MMU_BOOKE: cs->exception_index = POWERPC_EXCP_ITLB; env->error_code = 0; env->spr[SPR_BOOKE_DEAR] = address; + env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, 0); return -1; case POWERPC_MMU_MPC8xx: /* XXX: TODO */ @@ -1642,13 +1723,13 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, cpu_abort(cs, "MPC8xx MMU model is not implemented\n"); break; case POWERPC_MMU_BOOKE206: - booke206_update_mas_tlb_miss(env, address, rw); + booke206_update_mas_tlb_miss(env, address, rw, mmu_idx); /* fall through */ case POWERPC_MMU_BOOKE: cs->exception_index = POWERPC_EXCP_DTLB; env->error_code = 0; env->spr[SPR_BOOKE_DEAR] = address; - env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0; + env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, rw); return -1; case POWERPC_MMU_REAL: cpu_abort(cs, "PowerPC in real mode should never raise " @@ -1672,7 +1753,7 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, } else if ((env->mmu_model == POWERPC_MMU_BOOKE) || (env->mmu_model == POWERPC_MMU_BOOKE206)) { env->spr[SPR_BOOKE_DEAR] = address; - env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0; + env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, rw); } else { env->spr[SPR_DAR] = address; if (rw == 1) { @@ -2598,6 +2679,19 @@ void helper_booke_setpid(CPUPPCState *env, uint32_t pidn, target_ulong pid) tlb_flush(CPU(cpu)); } +void helper_booke_set_eplc(CPUPPCState *env, target_ulong val) +{ + PowerPCCPU *cpu = ppc_env_get_cpu(env); + env->spr[SPR_BOOKE_EPLC] = val & EPID_MASK; + tlb_flush_by_mmuidx(CPU(cpu), 1 << PPC_TLB_EPID_LOAD); +} +void helper_booke_set_epsc(CPUPPCState *env, target_ulong val) +{ + PowerPCCPU *cpu = ppc_env_get_cpu(env); + env->spr[SPR_BOOKE_EPSC] = val & EPID_MASK; + tlb_flush_by_mmuidx(CPU(cpu), 1 << PPC_TLB_EPID_STORE); +} + static inline void flush_page(CPUPPCState *env, ppcmas_tlb_t *tlb) { PowerPCCPU *cpu = ppc_env_get_cpu(env); diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 4e59dd5f42..2b37910248 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -2579,6 +2579,26 @@ GEN_LDS(lha, ld16s, 0x0A, PPC_INTEGER); GEN_LDS(lhz, ld16u, 0x08, PPC_INTEGER); /* lwz lwzu lwzux lwzx */ GEN_LDS(lwz, ld32u, 0x00, PPC_INTEGER); + +#define GEN_LDEPX(name, ldop, opc2, opc3) \ +static void glue(gen_, name##epx)(DisasContext *ctx) \ +{ \ + TCGv EA; \ + CHK_SV; \ + gen_set_access_type(ctx, ACCESS_INT); \ + EA = tcg_temp_new(); \ + gen_addr_reg_index(ctx, EA); \ + tcg_gen_qemu_ld_tl(cpu_gpr[rD(ctx->opcode)], EA, PPC_TLB_EPID_LOAD, ldop);\ + tcg_temp_free(EA); \ +} + +GEN_LDEPX(lb, DEF_MEMOP(MO_UB), 0x1F, 0x02) +GEN_LDEPX(lh, DEF_MEMOP(MO_UW), 0x1F, 0x08) +GEN_LDEPX(lw, DEF_MEMOP(MO_UL), 0x1F, 0x00) +#if defined(TARGET_PPC64) +GEN_LDEPX(ld, DEF_MEMOP(MO_Q), 0x1D, 0x00) +#endif + #if defined(TARGET_PPC64) /* lwaux */ GEN_LDUX(lwa, ld32s, 0x15, 0x0B, PPC_64B); @@ -2760,6 +2780,27 @@ GEN_STS(stb, st8, 0x06, PPC_INTEGER); GEN_STS(sth, st16, 0x0C, PPC_INTEGER); /* stw stwu stwux stwx */ GEN_STS(stw, st32, 0x04, PPC_INTEGER); + +#define GEN_STEPX(name, stop, opc2, opc3) \ +static void glue(gen_, name##epx)(DisasContext *ctx) \ +{ \ + TCGv EA; \ + CHK_SV; \ + gen_set_access_type(ctx, ACCESS_INT); \ + EA = tcg_temp_new(); \ + gen_addr_reg_index(ctx, EA); \ + tcg_gen_qemu_st_tl( \ + cpu_gpr[rD(ctx->opcode)], EA, PPC_TLB_EPID_STORE, stop); \ + tcg_temp_free(EA); \ +} + +GEN_STEPX(stb, DEF_MEMOP(MO_UB), 0x1F, 0x06) +GEN_STEPX(sth, DEF_MEMOP(MO_UW), 0x1F, 0x0C) +GEN_STEPX(stw, DEF_MEMOP(MO_UL), 0x1F, 0x04) +#if defined(TARGET_PPC64) +GEN_STEPX(std, DEF_MEMOP(MO_Q), 0x1d, 0x04) +#endif + #if defined(TARGET_PPC64) GEN_STUX(std, st64_i64, 0x15, 0x05, PPC_64B); GEN_STX(std, st64_i64, 0x15, 0x04, PPC_64B); @@ -3878,9 +3919,15 @@ static void gen_rfi(DisasContext *ctx) } /* Restore CPU state */ CHK_SV; + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { + gen_io_start(); + } gen_update_cfar(ctx, ctx->base.pc_next - 4); gen_helper_rfi(cpu_env); gen_sync_exception(ctx); + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { + gen_io_end(); + } #endif } @@ -3892,9 +3939,15 @@ static void gen_rfid(DisasContext *ctx) #else /* Restore CPU state */ CHK_SV; + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { + gen_io_start(); + } gen_update_cfar(ctx, ctx->base.pc_next - 4); gen_helper_rfid(cpu_env); gen_sync_exception(ctx); + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { + gen_io_end(); + } #endif } @@ -4257,11 +4310,17 @@ static void gen_mtmsrd(DisasContext *ctx) * if we enter power saving mode, we will exit the loop * directly from ppc_store_msr */ + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { + gen_io_start(); + } gen_update_nip(ctx, ctx->base.pc_next); gen_helper_store_msr(cpu_env, cpu_gpr[rS(ctx->opcode)]); /* Must stop the translation as machine state (may have) changed */ /* Note that mtmsr is not always defined as context-synchronizing */ gen_stop_exception(ctx); + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { + gen_io_end(); + } } #endif /* !defined(CONFIG_USER_ONLY) */ } @@ -4286,6 +4345,9 @@ static void gen_mtmsr(DisasContext *ctx) * if we enter power saving mode, we will exit the loop * directly from ppc_store_msr */ + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { + gen_io_start(); + } gen_update_nip(ctx, ctx->base.pc_next); #if defined(TARGET_PPC64) tcg_gen_deposit_tl(msr, cpu_msr, cpu_gpr[rS(ctx->opcode)], 0, 32); @@ -4293,6 +4355,9 @@ static void gen_mtmsr(DisasContext *ctx) tcg_gen_mov_tl(msr, cpu_gpr[rS(ctx->opcode)]); #endif gen_helper_store_msr(cpu_env, msr); + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { + gen_io_end(); + } tcg_temp_free(msr); /* Must stop the translation as machine state (may have) changed */ /* Note that mtmsr is not always defined as context-synchronizing */ @@ -4392,6 +4457,19 @@ static void gen_dcbf(DisasContext *ctx) tcg_temp_free(t0); } +/* dcbfep (external PID dcbf) */ +static void gen_dcbfep(DisasContext *ctx) +{ + /* XXX: specification says this is treated as a load by the MMU */ + TCGv t0; + CHK_SV; + gen_set_access_type(ctx, ACCESS_CACHE); + t0 = tcg_temp_new(); + gen_addr_reg_index(ctx, t0); + tcg_gen_qemu_ld_tl(t0, t0, PPC_TLB_EPID_LOAD, DEF_MEMOP(MO_UB)); + tcg_temp_free(t0); +} + /* dcbi (Supervisor only) */ static void gen_dcbi(DisasContext *ctx) { @@ -4425,6 +4503,18 @@ static void gen_dcbst(DisasContext *ctx) tcg_temp_free(t0); } +/* dcbstep (dcbstep External PID version) */ +static void gen_dcbstep(DisasContext *ctx) +{ + /* XXX: specification say this is treated as a load by the MMU */ + TCGv t0; + gen_set_access_type(ctx, ACCESS_CACHE); + t0 = tcg_temp_new(); + gen_addr_reg_index(ctx, t0); + tcg_gen_qemu_ld_tl(t0, t0, PPC_TLB_EPID_LOAD, DEF_MEMOP(MO_UB)); + tcg_temp_free(t0); +} + /* dcbt */ static void gen_dcbt(DisasContext *ctx) { @@ -4434,6 +4524,15 @@ static void gen_dcbt(DisasContext *ctx) */ } +/* dcbtep */ +static void gen_dcbtep(DisasContext *ctx) +{ + /* interpreted as no-op */ + /* XXX: specification say this is treated as a load by the MMU + * but does not generate any exception + */ +} + /* dcbtst */ static void gen_dcbtst(DisasContext *ctx) { @@ -4443,6 +4542,15 @@ static void gen_dcbtst(DisasContext *ctx) */ } +/* dcbtstep */ +static void gen_dcbtstep(DisasContext *ctx) +{ + /* interpreted as no-op */ + /* XXX: specification say this is treated as a load by the MMU + * but does not generate any exception + */ +} + /* dcbtls */ static void gen_dcbtls(DisasContext *ctx) { @@ -4469,6 +4577,21 @@ static void gen_dcbz(DisasContext *ctx) tcg_temp_free_i32(tcgv_op); } +/* dcbzep */ +static void gen_dcbzep(DisasContext *ctx) +{ + TCGv tcgv_addr; + TCGv_i32 tcgv_op; + + gen_set_access_type(ctx, ACCESS_CACHE); + tcgv_addr = tcg_temp_new(); + tcgv_op = tcg_const_i32(ctx->opcode & 0x03FF000); + gen_addr_reg_index(ctx, tcgv_addr); + gen_helper_dcbzep(cpu_env, tcgv_addr, tcgv_op); + tcg_temp_free(tcgv_addr); + tcg_temp_free_i32(tcgv_op); +} + /* dst / dstt */ static void gen_dst(DisasContext *ctx) { @@ -4507,6 +4630,17 @@ static void gen_icbi(DisasContext *ctx) tcg_temp_free(t0); } +/* icbiep */ +static void gen_icbiep(DisasContext *ctx) +{ + TCGv t0; + gen_set_access_type(ctx, ACCESS_CACHE); + t0 = tcg_temp_new(); + gen_addr_reg_index(ctx, t0); + gen_helper_icbiep(cpu_env, t0); + tcg_temp_free(t0); +} + /* Optional: */ /* dcba */ static void gen_dcba(DisasContext *ctx) @@ -6774,16 +6908,22 @@ GEN_HANDLER_E(mcrxrx, 0x1F, 0x00, 0x12, 0x007FF801, PPC_NONE, PPC2_ISA300), GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001EF801, PPC_MISC), GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000000, PPC_MISC), GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03C00001, PPC_CACHE), +GEN_HANDLER_E(dcbfep, 0x1F, 0x1F, 0x03, 0x03C00001, PPC_NONE, PPC2_BOOKE206), GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE), GEN_HANDLER(dcbst, 0x1F, 0x16, 0x01, 0x03E00001, PPC_CACHE), +GEN_HANDLER_E(dcbstep, 0x1F, 0x1F, 0x01, 0x03E00001, PPC_NONE, PPC2_BOOKE206), GEN_HANDLER(dcbt, 0x1F, 0x16, 0x08, 0x00000001, PPC_CACHE), +GEN_HANDLER_E(dcbtep, 0x1F, 0x1F, 0x09, 0x00000001, PPC_NONE, PPC2_BOOKE206), GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x00000001, PPC_CACHE), +GEN_HANDLER_E(dcbtstep, 0x1F, 0x1F, 0x07, 0x00000001, PPC_NONE, PPC2_BOOKE206), GEN_HANDLER_E(dcbtls, 0x1F, 0x06, 0x05, 0x02000001, PPC_BOOKE, PPC2_BOOKE206), GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03C00001, PPC_CACHE_DCBZ), +GEN_HANDLER_E(dcbzep, 0x1F, 0x1F, 0x1F, 0x03C00001, PPC_NONE, PPC2_BOOKE206), GEN_HANDLER(dst, 0x1F, 0x16, 0x0A, 0x01800001, PPC_ALTIVEC), GEN_HANDLER(dstst, 0x1F, 0x16, 0x0B, 0x01800001, PPC_ALTIVEC), GEN_HANDLER(dss, 0x1F, 0x16, 0x19, 0x019FF801, PPC_ALTIVEC), GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_CACHE_ICBI), +GEN_HANDLER_E(icbiep, 0x1F, 0x1F, 0x1E, 0x03E00001, PPC_NONE, PPC2_BOOKE206), GEN_HANDLER(dcba, 0x1F, 0x16, 0x17, 0x03E00001, PPC_CACHE_DCBA), GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT), GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT), @@ -7086,6 +7226,19 @@ GEN_LDX_HVRM(lbzcix, ld8u, 0x15, 0x1a, PPC_CILDST) GEN_LDX(lhbr, ld16ur, 0x16, 0x18, PPC_INTEGER) GEN_LDX(lwbr, ld32ur, 0x16, 0x10, PPC_INTEGER) +/* External PID based load */ +#undef GEN_LDEPX +#define GEN_LDEPX(name, ldop, opc2, opc3) \ +GEN_HANDLER_E(name##epx, 0x1F, opc2, opc3, \ + 0x00000001, PPC_NONE, PPC2_BOOKE206), + +GEN_LDEPX(lb, DEF_MEMOP(MO_UB), 0x1F, 0x02) +GEN_LDEPX(lh, DEF_MEMOP(MO_UW), 0x1F, 0x08) +GEN_LDEPX(lw, DEF_MEMOP(MO_UL), 0x1F, 0x00) +#if defined(TARGET_PPC64) +GEN_LDEPX(ld, DEF_MEMOP(MO_Q), 0x1D, 0x00) +#endif + #undef GEN_ST #undef GEN_STU #undef GEN_STUX @@ -7120,6 +7273,18 @@ GEN_STX_HVRM(stbcix, st8, 0x15, 0x1e, PPC_CILDST) GEN_STX(sthbr, st16r, 0x16, 0x1C, PPC_INTEGER) GEN_STX(stwbr, st32r, 0x16, 0x14, PPC_INTEGER) +#undef GEN_STEPX +#define GEN_STEPX(name, ldop, opc2, opc3) \ +GEN_HANDLER_E(name##epx, 0x1F, opc2, opc3, \ + 0x00000001, PPC_NONE, PPC2_BOOKE206), + +GEN_STEPX(stb, DEF_MEMOP(MO_UB), 0x1F, 0x06) +GEN_STEPX(sth, DEF_MEMOP(MO_UW), 0x1F, 0x0C) +GEN_STEPX(stw, DEF_MEMOP(MO_UL), 0x1F, 0x04) +#if defined(TARGET_PPC64) +GEN_STEPX(std, DEF_MEMOP(MO_Q), 0x1D, 0x04) +#endif + #undef GEN_CRLOGIC #define GEN_CRLOGIC(name, tcg_op, opc) \ GEN_HANDLER(name, 0x13, 0x01, opc, 0x00000001, PPC_INTEGER) diff --git a/target/ppc/translate/fp-impl.inc.c b/target/ppc/translate/fp-impl.inc.c index a6f522b85c..08770ba9f5 100644 --- a/target/ppc/translate/fp-impl.inc.c +++ b/target/ppc/translate/fp-impl.inc.c @@ -673,6 +673,23 @@ GEN_LDFS(lfd, ld64_i64, 0x12, PPC_FLOAT); /* lfs lfsu lfsux lfsx */ GEN_LDFS(lfs, ld32fs, 0x10, PPC_FLOAT); +/* lfdepx (external PID lfdx) */ +static void gen_lfdepx(DisasContext *ctx) +{ + TCGv EA; + CHK_SV; + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + gen_set_access_type(ctx, ACCESS_FLOAT); + EA = tcg_temp_new(); + gen_addr_reg_index(ctx, EA); + tcg_gen_qemu_ld_i64(cpu_fpr[rD(ctx->opcode)], EA, PPC_TLB_EPID_LOAD, + DEF_MEMOP(MO_Q)); + tcg_temp_free(EA); +} + /* lfdp */ static void gen_lfdp(DisasContext *ctx) { @@ -846,6 +863,23 @@ GEN_STFS(stfd, st64_i64, 0x16, PPC_FLOAT); /* stfs stfsu stfsux stfsx */ GEN_STFS(stfs, st32fs, 0x14, PPC_FLOAT); +/* stfdepx (external PID lfdx) */ +static void gen_stfdepx(DisasContext *ctx) +{ + TCGv EA; + CHK_SV; + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + gen_set_access_type(ctx, ACCESS_FLOAT); + EA = tcg_temp_new(); + gen_addr_reg_index(ctx, EA); + tcg_gen_qemu_st_i64(cpu_fpr[rD(ctx->opcode)], EA, PPC_TLB_EPID_STORE, + DEF_MEMOP(MO_Q)); + tcg_temp_free(EA); +} + /* stfdp */ static void gen_stfdp(DisasContext *ctx) { diff --git a/target/ppc/translate/fp-ops.inc.c b/target/ppc/translate/fp-ops.inc.c index 3c6d05a074..621f6bfe0c 100644 --- a/target/ppc/translate/fp-ops.inc.c +++ b/target/ppc/translate/fp-ops.inc.c @@ -66,6 +66,7 @@ GEN_LDXF(name, ldop, 0x17, op | 0x00, type) GEN_LDFS(lfd, ld64, 0x12, PPC_FLOAT) GEN_LDFS(lfs, ld32fs, 0x10, PPC_FLOAT) +GEN_HANDLER_E(lfdepx, 0x1F, 0x1F, 0x12, 0x00000001, PPC_NONE, PPC2_BOOKE206), GEN_HANDLER_E(lfiwax, 0x1f, 0x17, 0x1a, 0x00000001, PPC_NONE, PPC2_ISA205), GEN_HANDLER_E(lfiwzx, 0x1f, 0x17, 0x1b, 0x1, PPC_NONE, PPC2_FP_CVT_ISA206), GEN_HANDLER_E(lfdpx, 0x1F, 0x17, 0x18, 0x00200001, PPC_NONE, PPC2_ISA205), @@ -87,6 +88,7 @@ GEN_STXF(name, stop, 0x17, op | 0x00, type) GEN_STFS(stfd, st64_i64, 0x16, PPC_FLOAT) GEN_STFS(stfs, st32fs, 0x14, PPC_FLOAT) GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX) +GEN_HANDLER_E(stfdepx, 0x1F, 0x1F, 0x16, 0x00000001, PPC_NONE, PPC2_BOOKE206), GEN_HANDLER_E(stfdpx, 0x1F, 0x17, 0x1C, 0x00200001, PPC_NONE, PPC2_ISA205), GEN_HANDLER(frsqrtes, 0x3B, 0x1A, 0xFF, 0x001F07C0, PPC_FLOAT_FRSQRTES), diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c index ee9432eb15..168d0cec28 100644 --- a/target/ppc/translate_init.inc.c +++ b/target/ppc/translate_init.inc.c @@ -1653,6 +1653,15 @@ static void spr_write_booke_pid(DisasContext *ctx, int sprn, int gprn) gen_helper_booke_setpid(cpu_env, t0, cpu_gpr[gprn]); tcg_temp_free_i32(t0); } +static void spr_write_eplc(DisasContext *ctx, int sprn, int gprn) +{ + gen_helper_booke_set_eplc(cpu_env, cpu_gpr[gprn]); +} +static void spr_write_epsc(DisasContext *ctx, int sprn, int gprn) +{ + gen_helper_booke_set_epsc(cpu_env, cpu_gpr[gprn]); +} + #endif static void gen_spr_usprg3(CPUPPCState *env) @@ -1912,6 +1921,16 @@ static void gen_spr_BookE206(CPUPPCState *env, uint32_t mas_mask, &spr_read_generic, &spr_write_booke_pid, 0x00000000); } + + spr_register(env, SPR_BOOKE_EPLC, "EPLC", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_eplc, + 0x00000000); + spr_register(env, SPR_BOOKE_EPSC, "EPSC", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_epsc, + 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_MMUCFG, "MMUCFG", SPR_NOACCESS, SPR_NOACCESS, @@ -2797,8 +2816,6 @@ static void gen_spr_8xx(CPUPPCState *env) * perf => 768-783 (Power 2.04) * perf => 784-799 (Power 2.04) * PPR => SPR 896 (Power 2.04) - * EPLC => SPR 947 (Power 2.04 emb) - * EPSC => SPR 948 (Power 2.04 emb) * DABRX => 1015 (Power 2.04 hypv) * FPECR => SPR 1022 (?) * ... and more (thermal management, performance counters, ...) @@ -8197,11 +8214,11 @@ static void gen_spr_power9_mmu(CPUPPCState *env) { #if !defined(CONFIG_USER_ONLY) /* Partition Table Control */ - spr_register_hv(env, SPR_PTCR, "PTCR", - SPR_NOACCESS, SPR_NOACCESS, - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_ptcr, - 0x00000000); + spr_register_kvm_hv(env, SPR_PTCR, "PTCR", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_ptcr, + KVM_REG_PPC_PTCR, 0x00000000); #endif } |