summaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2017-03-04 16:31:14 +0000
committerPeter Maydell <peter.maydell@linaro.org>2017-03-04 16:31:14 +0000
commit17783ac828adc694d986698d2d7014aedfeb48c6 (patch)
tree26dd4777eb9f4c8a7882a1cb5bc171e7c89a239e /target
parenteeb61d4f8270a6849d9a584fc83da3869b79066d (diff)
parent992d7e976c7eca2b3129cd4bae4a0d350a8065fa (diff)
downloadqemu-17783ac828adc694d986698d2d7014aedfeb48c6.tar.gz
Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-2.9-20170303' into staging
ppc patch queuye for 2017-03-03 This will probably be my last pull request before the hard freeze. It has some new work, but that has all been posted in draft before the soft freeze, so I think it's reasonable to include in qemu-2.9. This batch has: * A substantial amount of POWER9 work * Implements the legacy (hash) MMU for POWER9 * Some more preliminaries for implementing the POWER9 radix MMU * POWER9 has_work * Basic POWER9 compatibility mode handling * Removal of some premature tests * Some cleanups and fixes to the existing MMU code to make the POWER9 work simpler * A bugfix for TCG multiply adds on power * Allow pseries guests to access PCIe extended config space This also includes a code-motion not strictly in ppc code - moving getrampagesize() from ppc code to exec.c. This will make some future VFIO improvements easier, Paolo said it was ok to merge via my tree. # gpg: Signature made Fri 03 Mar 2017 03:20:36 GMT # gpg: using RSA key 0x6C38CACA20D9B392 # 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-2.9-20170303: target/ppc: rewrite f[n]m[add,sub] using float64_muladd spapr: Small cleanup of PPC MMU enums spapr_pci: Advertise access to PCIe extended config space target/ppc: Rework hash mmu page fault code and add defines for clarity target/ppc: Move no-execute and guarded page checking into new function target/ppc: Add execute permission checking to access authority check target/ppc: Add Instruction Authority Mask Register Check hw/ppc/spapr: Add POWER9 to pseries cpu models target/ppc/POWER9: Add cpu_has_work function for POWER9 target/ppc/POWER9: Add POWER9 pa-features definition target/ppc/POWER9: Add POWER9 mmu fault handler target/ppc: Don't gen an SDR1 on POWER9 and rework register creation target/ppc: Add patb_entry to sPAPRMachineState target/ppc/POWER9: Add POWERPC_MMU_V3 bit powernv: Don't test POWER9 CPU yet exec, kvm, target-ppc: Move getrampagesize() to common code target/ppc: Add POWER9/ISAv3.00 to compat_table Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target')
-rw-r--r--target/ppc/Makefile.objs2
-rw-r--r--target/ppc/compat.c16
-rw-r--r--target/ppc/cpu-qom.h16
-rw-r--r--target/ppc/cpu.h17
-rw-r--r--target/ppc/fpu_helper.c213
-rw-r--r--target/ppc/kvm.c117
-rw-r--r--target/ppc/mmu-book3s-v3.c37
-rw-r--r--target/ppc/mmu-book3s-v3.h50
-rw-r--r--target/ppc/mmu-hash64.c117
-rw-r--r--target/ppc/mmu_helper.c82
-rw-r--r--target/ppc/translate.c19
-rw-r--r--target/ppc/translate_init.c364
12 files changed, 562 insertions, 488 deletions
diff --git a/target/ppc/Makefile.objs b/target/ppc/Makefile.objs
index 0057b319c0..f963777277 100644
--- a/target/ppc/Makefile.objs
+++ b/target/ppc/Makefile.objs
@@ -3,7 +3,7 @@ obj-y += cpu.o
obj-y += translate.o
ifeq ($(CONFIG_SOFTMMU),y)
obj-y += machine.o mmu_helper.o mmu-hash32.o monitor.o arch_dump.o
-obj-$(TARGET_PPC64) += mmu-hash64.o compat.o
+obj-$(TARGET_PPC64) += mmu-hash64.o mmu-book3s-v3.o compat.o
endif
obj-$(CONFIG_KVM) += kvm.o
obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
diff --git a/target/ppc/compat.c b/target/ppc/compat.c
index 458da262be..e8ec1e19e7 100644
--- a/target/ppc/compat.c
+++ b/target/ppc/compat.c
@@ -39,29 +39,35 @@ static const CompatInfo compat_table[] = {
*/
{ /* POWER6, ISA2.05 */
.pvr = CPU_POWERPC_LOGICAL_2_05,
- .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05
- | PCR_TM_DIS | PCR_VSX_DIS,
+ .pcr = PCR_COMPAT_3_00 | PCR_COMPAT_2_07 | PCR_COMPAT_2_06 |
+ PCR_COMPAT_2_05 | PCR_TM_DIS | PCR_VSX_DIS,
.pcr_level = PCR_COMPAT_2_05,
.max_threads = 2,
},
{ /* POWER7, ISA2.06 */
.pvr = CPU_POWERPC_LOGICAL_2_06,
- .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
+ .pcr = PCR_COMPAT_3_00 | PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
.pcr_level = PCR_COMPAT_2_06,
.max_threads = 4,
},
{
.pvr = CPU_POWERPC_LOGICAL_2_06_PLUS,
- .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
+ .pcr = PCR_COMPAT_3_00 | PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
.pcr_level = PCR_COMPAT_2_06,
.max_threads = 4,
},
{ /* POWER8, ISA2.07 */
.pvr = CPU_POWERPC_LOGICAL_2_07,
- .pcr = PCR_COMPAT_2_07,
+ .pcr = PCR_COMPAT_3_00 | PCR_COMPAT_2_07,
.pcr_level = PCR_COMPAT_2_07,
.max_threads = 8,
},
+ { /* POWER9, ISA3.00 */
+ .pvr = CPU_POWERPC_LOGICAL_3_00,
+ .pcr = PCR_COMPAT_3_00,
+ .pcr_level = PCR_COMPAT_3_00,
+ .max_threads = 4,
+ },
};
static const CompatInfo *compat_by_pvr(uint32_t pvr)
diff --git a/target/ppc/cpu-qom.h b/target/ppc/cpu-qom.h
index 4e3132b56b..81500e5748 100644
--- a/target/ppc/cpu-qom.h
+++ b/target/ppc/cpu-qom.h
@@ -71,6 +71,7 @@ enum powerpc_mmu_t {
#define POWERPC_MMU_1TSEG 0x00020000
#define POWERPC_MMU_AMR 0x00040000
#define POWERPC_MMU_64K 0x00080000
+#define POWERPC_MMU_V3 0x00100000 /* ISA V3.00 MMU Support */
/* 64 bits PowerPC MMU */
POWERPC_MMU_64B = POWERPC_MMU_64 | 0x00000001,
/* Architecture 2.03 and later (has LPCR) */
@@ -79,21 +80,22 @@ enum powerpc_mmu_t {
POWERPC_MMU_2_06 = POWERPC_MMU_64 | POWERPC_MMU_1TSEG
| POWERPC_MMU_64K
| POWERPC_MMU_AMR | 0x00000003,
- /* Architecture 2.06 "degraded" (no 1T segments) */
- POWERPC_MMU_2_06a = POWERPC_MMU_64 | POWERPC_MMU_AMR
- | 0x00000003,
/* Architecture 2.07 variant */
POWERPC_MMU_2_07 = POWERPC_MMU_64 | POWERPC_MMU_1TSEG
| POWERPC_MMU_64K
| POWERPC_MMU_AMR | 0x00000004,
- /* Architecture 2.07 "degraded" (no 1T segments) */
- POWERPC_MMU_2_07a = POWERPC_MMU_64 | POWERPC_MMU_AMR
- | 0x00000004,
/* Architecture 3.00 variant */
POWERPC_MMU_3_00 = POWERPC_MMU_64 | POWERPC_MMU_1TSEG
| POWERPC_MMU_64K
- | POWERPC_MMU_AMR | 0x00000005,
+ | POWERPC_MMU_AMR | POWERPC_MMU_V3
+ | 0x00000005,
};
+#define POWERPC_MMU_VER(x) ((x) & (POWERPC_MMU_64 | 0xFFFF))
+#define POWERPC_MMU_VER_64B POWERPC_MMU_VER(POWERPC_MMU_64B)
+#define POWERPC_MMU_VER_2_03 POWERPC_MMU_VER(POWERPC_MMU_2_03)
+#define POWERPC_MMU_VER_2_06 POWERPC_MMU_VER(POWERPC_MMU_2_06)
+#define POWERPC_MMU_VER_2_07 POWERPC_MMU_VER(POWERPC_MMU_2_07)
+#define POWERPC_MMU_VER_3_00 POWERPC_MMU_VER(POWERPC_MMU_3_00)
/*****************************************************************************/
/* Exception model */
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index d33c17e646..7c4a1f50b3 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -473,6 +473,22 @@ struct ppc_slb_t {
#endif
#endif
+/* DSISR */
+#define DSISR_NOPTE 0x40000000
+/* Not permitted by access authority of encoded access authority */
+#define DSISR_PROTFAULT 0x08000000
+#define DSISR_ISSTORE 0x02000000
+/* Not permitted by virtual page class key protection */
+#define DSISR_AMR 0x00200000
+
+/* SRR1 error code fields */
+
+#define SRR1_NOPTE DSISR_NOPTE
+/* Not permitted due to no-execute or guard bit set */
+#define SRR1_NOEXEC_GUARD 0x10000000
+#define SRR1_PROTFAULT DSISR_PROTFAULT
+#define SRR1_IAMR DSISR_AMR
+
/* Facility Status and Control (FSCR) bits */
#define FSCR_EBB (63 - 56) /* Event-Based Branch Facility */
#define FSCR_TAR (63 - 55) /* Target Address Register */
@@ -1216,6 +1232,7 @@ struct PPCVirtualHypervisorClass {
hwaddr ptex, int n);
void (*store_hpte)(PPCVirtualHypervisor *vhyp, hwaddr ptex,
uint64_t pte0, uint64_t pte1);
+ uint64_t (*get_patbe)(PPCVirtualHypervisor *vhyp);
};
#define TYPE_PPC_VIRTUAL_HYPERVISOR "ppc-virtual-hypervisor"
diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c
index 58aee640c3..0535ad0814 100644
--- a/target/ppc/fpu_helper.c
+++ b/target/ppc/fpu_helper.c
@@ -743,178 +743,62 @@ uint64_t helper_frim(CPUPPCState *env, uint64_t arg)
return do_fri(env, arg, float_round_down);
}
-/* fmadd - fmadd. */
-uint64_t helper_fmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
- uint64_t arg3)
+static void float64_maddsub_update_excp(CPUPPCState *env, float64 arg1,
+ float64 arg2, float64 arg3,
+ unsigned int madd_flags)
{
- CPU_DoubleU farg1, farg2, farg3;
-
- farg1.ll = arg1;
- farg2.ll = arg2;
- farg3.ll = arg3;
-
- if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
- (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
- /* Multiplication of zero by infinity */
- farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
- } else {
- if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
- float64_is_signaling_nan(farg2.d, &env->fp_status) ||
- float64_is_signaling_nan(farg3.d, &env->fp_status))) {
- /* sNaN operation */
- float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
- }
- /* This is the way the PowerPC specification defines it */
- float128 ft0_128, ft1_128;
-
- ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
- ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
- ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
- if (unlikely(float128_is_infinity(ft0_128) &&
- float64_is_infinity(farg3.d) &&
- float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
- /* Magnitude subtraction of infinities */
- farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
- } else {
- ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
- ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
- farg1.d = float128_to_float64(ft0_128, &env->fp_status);
- }
- }
-
- return farg1.ll;
-}
-
-/* fmsub - fmsub. */
-uint64_t helper_fmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
- uint64_t arg3)
-{
- CPU_DoubleU farg1, farg2, farg3;
-
- farg1.ll = arg1;
- farg2.ll = arg2;
- farg3.ll = arg3;
-
- if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
- (float64_is_zero(farg1.d) &&
- float64_is_infinity(farg2.d)))) {
+ if (unlikely((float64_is_infinity(arg1) && float64_is_zero(arg2)) ||
+ (float64_is_zero(arg1) && float64_is_infinity(arg2)))) {
/* Multiplication of zero by infinity */
- farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
- } else {
- if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
- float64_is_signaling_nan(farg2.d, &env->fp_status) ||
- float64_is_signaling_nan(farg3.d, &env->fp_status))) {
- /* sNaN operation */
- float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+ arg1 = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
+ } else if (unlikely(float64_is_signaling_nan(arg1, &env->fp_status) ||
+ float64_is_signaling_nan(arg2, &env->fp_status) ||
+ float64_is_signaling_nan(arg3, &env->fp_status))) {
+ /* sNaN operation */
+ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+ } else if ((float64_is_infinity(arg1) || float64_is_infinity(arg2)) &&
+ float64_is_infinity(arg3)) {
+ uint8_t aSign, bSign, cSign;
+
+ aSign = float64_is_neg(arg1);
+ bSign = float64_is_neg(arg2);
+ cSign = float64_is_neg(arg3);
+ if (madd_flags & float_muladd_negate_c) {
+ cSign ^= 1;
}
- /* This is the way the PowerPC specification defines it */
- float128 ft0_128, ft1_128;
-
- ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
- ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
- ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
- if (unlikely(float128_is_infinity(ft0_128) &&
- float64_is_infinity(farg3.d) &&
- float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
- /* Magnitude subtraction of infinities */
- farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
- } else {
- ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
- ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
- farg1.d = float128_to_float64(ft0_128, &env->fp_status);
+ if (aSign ^ bSign ^ cSign) {
+ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
}
}
- return farg1.ll;
}
-/* fnmadd - fnmadd. */
-uint64_t helper_fnmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
- uint64_t arg3)
-{
- CPU_DoubleU farg1, farg2, farg3;
-
- farg1.ll = arg1;
- farg2.ll = arg2;
- farg3.ll = arg3;
-
- if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
- (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
- /* Multiplication of zero by infinity */
- farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
- } else {
- if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
- float64_is_signaling_nan(farg2.d, &env->fp_status) ||
- float64_is_signaling_nan(farg3.d, &env->fp_status))) {
- /* sNaN operation */
- float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
- }
- /* This is the way the PowerPC specification defines it */
- float128 ft0_128, ft1_128;
-
- ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
- ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
- ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
- if (unlikely(float128_is_infinity(ft0_128) &&
- float64_is_infinity(farg3.d) &&
- float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
- /* Magnitude subtraction of infinities */
- farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
- } else {
- ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
- ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
- farg1.d = float128_to_float64(ft0_128, &env->fp_status);
- }
- if (likely(!float64_is_any_nan(farg1.d))) {
- farg1.d = float64_chs(farg1.d);
- }
- }
- return farg1.ll;
+#define FPU_FMADD(op, madd_flags) \
+uint64_t helper_##op(CPUPPCState *env, uint64_t arg1, \
+ uint64_t arg2, uint64_t arg3) \
+{ \
+ uint32_t flags; \
+ float64 ret = float64_muladd(arg1, arg2, arg3, madd_flags, \
+ &env->fp_status); \
+ flags = get_float_exception_flags(&env->fp_status); \
+ if (flags) { \
+ if (flags & float_flag_invalid) { \
+ float64_maddsub_update_excp(env, arg1, arg2, arg3, \
+ madd_flags); \
+ } \
+ float_check_status(env); \
+ } \
+ return ret; \
}
-/* fnmsub - fnmsub. */
-uint64_t helper_fnmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
- uint64_t arg3)
-{
- CPU_DoubleU farg1, farg2, farg3;
-
- farg1.ll = arg1;
- farg2.ll = arg2;
- farg3.ll = arg3;
+#define MADD_FLGS 0
+#define MSUB_FLGS float_muladd_negate_c
+#define NMADD_FLGS float_muladd_negate_result
+#define NMSUB_FLGS (float_muladd_negate_c | float_muladd_negate_result)
- if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
- (float64_is_zero(farg1.d) &&
- float64_is_infinity(farg2.d)))) {
- /* Multiplication of zero by infinity */
- farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
- } else {
- if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
- float64_is_signaling_nan(farg2.d, &env->fp_status) ||
- float64_is_signaling_nan(farg3.d, &env->fp_status))) {
- /* sNaN operation */
- float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
- }
- /* This is the way the PowerPC specification defines it */
- float128 ft0_128, ft1_128;
-
- ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
- ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
- ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
- if (unlikely(float128_is_infinity(ft0_128) &&
- float64_is_infinity(farg3.d) &&
- float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
- /* Magnitude subtraction of infinities */
- farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
- } else {
- ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
- ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
- farg1.d = float128_to_float64(ft0_128, &env->fp_status);
- }
- if (likely(!float64_is_any_nan(farg1.d))) {
- farg1.d = float64_chs(farg1.d);
- }
- }
- return farg1.ll;
-}
+FPU_FMADD(fmadd, MADD_FLGS)
+FPU_FMADD(fnmadd, NMADD_FLGS)
+FPU_FMADD(fmsub, MSUB_FLGS)
+FPU_FMADD(fnmsub, NMSUB_FLGS)
/* frsp - frsp. */
uint64_t helper_frsp(CPUPPCState *env, uint64_t arg)
@@ -2384,11 +2268,6 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
float_check_status(env); \
}
-#define MADD_FLGS 0
-#define MSUB_FLGS float_muladd_negate_c
-#define NMADD_FLGS float_muladd_negate_result
-#define NMSUB_FLGS (float_muladd_negate_c | float_muladd_negate_result)
-
VSX_MADD(xsmaddadp, 1, float64, VsrD(0), MADD_FLGS, 1, 1, 0)
VSX_MADD(xsmaddmdp, 1, float64, VsrD(0), MADD_FLGS, 0, 1, 0)
VSX_MADD(xsmsubadp, 1, float64, VsrD(0), MSUB_FLGS, 1, 1, 0)
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 03f5097eab..9f1f132cef 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -28,7 +28,6 @@
#include "qemu/timer.h"
#include "sysemu/sysemu.h"
#include "sysemu/hw_accel.h"
-#include "sysemu/numa.h"
#include "kvm_ppc.h"
#include "sysemu/cpus.h"
#include "sysemu/device_tree.h"
@@ -43,8 +42,10 @@
#include "trace.h"
#include "exec/gdbstub.h"
#include "exec/memattrs.h"
+#include "exec/ram_addr.h"
#include "sysemu/hostmem.h"
#include "qemu/cutils.h"
+#include "qemu/mmap-alloc.h"
#if defined(TARGET_PPC64)
#include "hw/ppc/spapr_cpu_core.h"
#endif
@@ -282,8 +283,8 @@ static void kvm_get_fallback_smmu_info(PowerPCCPU *cpu,
info->flags |= KVM_PPC_1T_SEGMENTS;
}
- if (env->mmu_model == POWERPC_MMU_2_06 ||
- env->mmu_model == POWERPC_MMU_2_07) {
+ if (POWERPC_MMU_VER(env->mmu_model) == POWERPC_MMU_VER_2_06 ||
+ POWERPC_MMU_VER(env->mmu_model) == POWERPC_MMU_VER_2_07) {
info->slb_size = 32;
} else {
info->slb_size = 64;
@@ -297,8 +298,8 @@ static void kvm_get_fallback_smmu_info(PowerPCCPU *cpu,
i++;
/* 64K on MMU 2.06 and later */
- if (env->mmu_model == POWERPC_MMU_2_06 ||
- env->mmu_model == POWERPC_MMU_2_07) {
+ if (POWERPC_MMU_VER(env->mmu_model) == POWERPC_MMU_VER_2_06 ||
+ POWERPC_MMU_VER(env->mmu_model) == POWERPC_MMU_VER_2_07) {
info->sps[i].page_shift = 16;
info->sps[i].slb_enc = 0x110;
info->sps[i].enc[0].page_shift = 16;
@@ -329,106 +330,6 @@ static void kvm_get_smmu_info(PowerPCCPU *cpu, struct kvm_ppc_smmu_info *info)
kvm_get_fallback_smmu_info(cpu, info);
}
-static long gethugepagesize(const char *mem_path)
-{
- struct statfs fs;
- int ret;
-
- do {
- ret = statfs(mem_path, &fs);
- } while (ret != 0 && errno == EINTR);
-
- if (ret != 0) {
- fprintf(stderr, "Couldn't statfs() memory path: %s\n",
- strerror(errno));
- exit(1);
- }
-
-#define HUGETLBFS_MAGIC 0x958458f6
-
- if (fs.f_type != HUGETLBFS_MAGIC) {
- /* Explicit mempath, but it's ordinary pages */
- return getpagesize();
- }
-
- /* It's hugepage, return the huge page size */
- return fs.f_bsize;
-}
-
-/*
- * FIXME TOCTTOU: this iterates over memory backends' mem-path, which
- * may or may not name the same files / on the same filesystem now as
- * when we actually open and map them. Iterate over the file
- * descriptors instead, and use qemu_fd_getpagesize().
- */
-static int find_max_supported_pagesize(Object *obj, void *opaque)
-{
- char *mem_path;
- long *hpsize_min = opaque;
-
- if (object_dynamic_cast(obj, TYPE_MEMORY_BACKEND)) {
- mem_path = object_property_get_str(obj, "mem-path", NULL);
- if (mem_path) {
- long hpsize = gethugepagesize(mem_path);
- if (hpsize < *hpsize_min) {
- *hpsize_min = hpsize;
- }
- } else {
- *hpsize_min = getpagesize();
- }
- }
-
- return 0;
-}
-
-static long getrampagesize(void)
-{
- long hpsize = LONG_MAX;
- long mainrampagesize;
- Object *memdev_root;
-
- if (mem_path) {
- mainrampagesize = gethugepagesize(mem_path);
- } else {
- mainrampagesize = getpagesize();
- }
-
- /* it's possible we have memory-backend objects with
- * hugepage-backed RAM. these may get mapped into system
- * address space via -numa parameters or memory hotplug
- * hooks. we want to take these into account, but we
- * also want to make sure these supported hugepage
- * sizes are applicable across the entire range of memory
- * we may boot from, so we take the min across all
- * backends, and assume normal pages in cases where a
- * backend isn't backed by hugepages.
- */
- memdev_root = object_resolve_path("/objects", NULL);
- if (memdev_root) {
- object_child_foreach(memdev_root, find_max_supported_pagesize, &hpsize);
- }
- if (hpsize == LONG_MAX) {
- /* No additional memory regions found ==> Report main RAM page size */
- return mainrampagesize;
- }
-
- /* If NUMA is disabled or the NUMA nodes are not backed with a
- * memory-backend, then there is at least one node using "normal" RAM,
- * so if its page size is smaller we have got to report that size instead.
- */
- if (hpsize > mainrampagesize &&
- (nb_numa_nodes == 0 || numa_info[0].node_memdev == NULL)) {
- static bool warned;
- if (!warned) {
- error_report("Huge page support disabled (n/a for main memory).");
- warned = true;
- }
- return mainrampagesize;
- }
-
- return hpsize;
-}
-
static bool kvm_valid_page_size(uint32_t flags, long rampgsize, uint32_t shift)
{
if (!(flags & KVM_PPC_PAGE_SIZES_REAL)) {
@@ -460,7 +361,7 @@ static void kvm_fixup_page_sizes(PowerPCCPU *cpu)
}
if (!max_cpu_page_size) {
- max_cpu_page_size = getrampagesize();
+ max_cpu_page_size = qemu_getrampagesize();
}
/* Convert to QEMU form */
@@ -521,7 +422,7 @@ bool kvmppc_is_mem_backend_page_size_ok(char *obj_path)
long pagesize;
if (mempath) {
- pagesize = gethugepagesize(mempath);
+ pagesize = qemu_mempath_getpagesize(mempath);
} else {
pagesize = getpagesize();
}
@@ -2205,7 +2106,7 @@ uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift)
/* Find the largest hardware supported page size that's less than
* or equal to the (logical) backing page size of guest RAM */
kvm_get_smmu_info(POWERPC_CPU(first_cpu), &info);
- rampagesize = getrampagesize();
+ rampagesize = qemu_getrampagesize();
best_page_shift = 0;
for (i = 0; i < KVM_PPC_PAGE_SIZES_MAX_SZ; i++) {
diff --git a/target/ppc/mmu-book3s-v3.c b/target/ppc/mmu-book3s-v3.c
new file mode 100644
index 0000000000..005c96340a
--- /dev/null
+++ b/target/ppc/mmu-book3s-v3.c
@@ -0,0 +1,37 @@
+/*
+ * PowerPC ISAV3 BookS emulation generic mmu helpers for qemu.
+ *
+ * Copyright (c) 2017 Suraj Jitindar Singh, IBM Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "cpu.h"
+#include "mmu-hash64.h"
+#include "mmu-book3s-v3.h"
+#include "qemu/error-report.h"
+
+int ppc64_v3_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
+ int mmu_idx)
+{
+ if (ppc64_radix_guest(cpu)) { /* Guest uses radix */
+ /* TODO - Unsupported */
+ error_report("Guest Radix Support Unimplemented");
+ exit(1);
+ } else { /* Guest uses hash */
+ return ppc_hash64_handle_mmu_fault(cpu, eaddr, rwx, mmu_idx);
+ }
+}
diff --git a/target/ppc/mmu-book3s-v3.h b/target/ppc/mmu-book3s-v3.h
new file mode 100644
index 0000000000..636f6ab95f
--- /dev/null
+++ b/target/ppc/mmu-book3s-v3.h
@@ -0,0 +1,50 @@
+/*
+ * PowerPC ISAV3 BookS emulation generic mmu definitions for qemu.
+ *
+ * Copyright (c) 2017 Suraj Jitindar Singh, IBM Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MMU_H
+#define MMU_H
+
+#ifndef CONFIG_USER_ONLY
+
+/* Partition Table Entry Fields */
+#define PATBE1_GR 0x8000000000000000
+
+#ifdef TARGET_PPC64
+
+static inline bool ppc64_use_proc_tbl(PowerPCCPU *cpu)
+{
+ return !!(cpu->env.spr[SPR_LPCR] & LPCR_UPRT);
+}
+
+static inline bool ppc64_radix_guest(PowerPCCPU *cpu)
+{
+ PPCVirtualHypervisorClass *vhc =
+ PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
+
+ return !!(vhc->get_patbe(cpu->vhyp) & PATBE1_GR);
+}
+
+int ppc64_v3_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
+ int mmu_idx);
+
+#endif /* TARGET_PPC64 */
+
+#endif /* CONFIG_USER_ONLY */
+
+#endif /* MMU_H */
diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
index d44f2bb432..14d34e512f 100644
--- a/target/ppc/mmu-hash64.c
+++ b/target/ppc/mmu-hash64.c
@@ -28,6 +28,7 @@
#include "mmu-hash64.h"
#include "exec/log.h"
#include "hw/hw.h"
+#include "mmu-book3s-v3.h"
//#define DEBUG_SLB
@@ -289,6 +290,16 @@ target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb)
return rt;
}
+/* Check No-Execute or Guarded Storage */
+static inline int ppc_hash64_pte_noexec_guard(PowerPCCPU *cpu,
+ ppc_hash_pte64_t pte)
+{
+ /* Exec permissions CANNOT take away read or write permissions */
+ return (pte.pte1 & HPTE64_R_N) || (pte.pte1 & HPTE64_R_G) ?
+ PAGE_READ | PAGE_WRITE : PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+}
+
+/* Check Basic Storage Protection */
static int ppc_hash64_pte_prot(PowerPCCPU *cpu,
ppc_slb_t *slb, ppc_hash_pte64_t pte)
{
@@ -307,41 +318,51 @@ static int ppc_hash64_pte_prot(PowerPCCPU *cpu,
case 0x0:
case 0x1:
case 0x2:
- prot = PAGE_READ | PAGE_WRITE;
+ prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
break;
case 0x3:
case 0x6:
- prot = PAGE_READ;
+ prot = PAGE_READ | PAGE_EXEC;
break;
}
} else {
switch (pp) {
case 0x0:
case 0x6:
- prot = 0;
break;
case 0x1:
case 0x3:
- prot = PAGE_READ;
+ prot = PAGE_READ | PAGE_EXEC;
break;
case 0x2:
- prot = PAGE_READ | PAGE_WRITE;
+ prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
break;
}
}
- /* No execute if either noexec or guarded bits set */
- if (!(pte.pte1 & HPTE64_R_N) || (pte.pte1 & HPTE64_R_G)
- || (slb->vsid & SLB_VSID_N)) {
- prot |= PAGE_EXEC;
- }
-
return prot;
}
+/* Check the instruction access permissions specified in the IAMR */
+static int ppc_hash64_iamr_prot(PowerPCCPU *cpu, int key)
+{
+ CPUPPCState *env = &cpu->env;
+ int iamr_bits = (env->spr[SPR_IAMR] >> 2 * (31 - key)) & 0x3;
+
+ /*
+ * An instruction fetch is permitted if the IAMR bit is 0.
+ * If the bit is set, return PAGE_READ | PAGE_WRITE because this bit
+ * can only take away EXEC permissions not READ or WRITE permissions.
+ * If bit is cleared return PAGE_READ | PAGE_WRITE | PAGE_EXEC since
+ * EXEC permissions are allowed.
+ */
+ return (iamr_bits & 0x1) ? PAGE_READ | PAGE_WRITE :
+ PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+}
+
static int ppc_hash64_amr_prot(PowerPCCPU *cpu, ppc_hash_pte64_t pte)
{
CPUPPCState *env = &cpu->env;
@@ -374,6 +395,21 @@ static int ppc_hash64_amr_prot(PowerPCCPU *cpu, ppc_hash_pte64_t pte)
prot &= ~PAGE_READ;
}
+ switch (env->mmu_model) {
+ /*
+ * MMU version 2.07 and later support IAMR
+ * Check if the IAMR allows the instruction access - it will return
+ * PAGE_EXEC if it doesn't (and thus that bit will be cleared) or 0
+ * if it does (and prot will be unchanged indicating execution support).
+ */
+ case POWERPC_MMU_2_07:
+ case POWERPC_MMU_3_00:
+ prot &= ppc_hash64_iamr_prot(cpu, key);
+ break;
+ default:
+ break;
+ }
+
return prot;
}
@@ -664,8 +700,8 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
unsigned apshift;
hwaddr ptex;
ppc_hash_pte64_t pte;
- int pp_prot, amr_prot, prot;
- uint64_t new_pte1, dsisr;
+ int exec_prot, pp_prot, amr_prot, prot;
+ uint64_t new_pte1;
const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC};
hwaddr raddr;
@@ -706,11 +742,11 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
} else {
/* The access failed, generate the approriate interrupt */
if (rwx == 2) {
- ppc_hash64_set_isi(cs, env, 0x08000000);
+ ppc_hash64_set_isi(cs, env, SRR1_PROTFAULT);
} else {
- dsisr = 0x08000000;
+ int dsisr = DSISR_PROTFAULT;
if (rwx == 1) {
- dsisr |= 0x02000000;
+ dsisr |= DSISR_ISSTORE;
}
ppc_hash64_set_dsi(cs, env, eaddr, dsisr);
}
@@ -726,6 +762,13 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
/* 2. Translation is on, so look up the SLB */
slb = slb_lookup(cpu, eaddr);
if (!slb) {
+ /* No entry found, check if in-memory segment tables are in use */
+ if ((env->mmu_model & POWERPC_MMU_V3) && ppc64_use_proc_tbl(cpu)) {
+ /* TODO - Unsupported */
+ error_report("Segment Table Support Unimplemented");
+ exit(1);
+ }
+ /* Segment still not found, generate the appropriate interrupt */
if (rwx == 2) {
cs->exception_index = POWERPC_EXCP_ISEG;
env->error_code = 0;
@@ -741,19 +784,19 @@ skip_slb_search:
/* 3. Check for segment level no-execute violation */
if ((rwx == 2) && (slb->vsid & SLB_VSID_N)) {
- ppc_hash64_set_isi(cs, env, 0x10000000);
+ ppc_hash64_set_isi(cs, env, SRR1_NOEXEC_GUARD);
return 1;
}
/* 4. Locate the PTE in the hash table */
ptex = ppc_hash64_htab_lookup(cpu, slb, eaddr, &pte, &apshift);
if (ptex == -1) {
- dsisr = 0x40000000;
if (rwx == 2) {
- ppc_hash64_set_isi(cs, env, dsisr);
+ ppc_hash64_set_isi(cs, env, SRR1_NOPTE);
} else {
+ int dsisr = DSISR_NOPTE;
if (rwx == 1) {
- dsisr |= 0x02000000;
+ dsisr |= DSISR_ISSTORE;
}
ppc_hash64_set_dsi(cs, env, eaddr, dsisr);
}
@@ -764,25 +807,35 @@ skip_slb_search:
/* 5. Check access permissions */
+ exec_prot = ppc_hash64_pte_noexec_guard(cpu, pte);
pp_prot = ppc_hash64_pte_prot(cpu, slb, pte);
amr_prot = ppc_hash64_amr_prot(cpu, pte);
- prot = pp_prot & amr_prot;
+ prot = exec_prot & pp_prot & amr_prot;
if ((need_prot[rwx] & ~prot) != 0) {
/* Access right violation */
qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
if (rwx == 2) {
- ppc_hash64_set_isi(cs, env, 0x08000000);
+ int srr1 = 0;
+ if (PAGE_EXEC & ~exec_prot) {
+ srr1 |= SRR1_NOEXEC_GUARD; /* Access violates noexec or guard */
+ } else if (PAGE_EXEC & ~pp_prot) {
+ srr1 |= SRR1_PROTFAULT; /* Access violates access authority */
+ }
+ if (PAGE_EXEC & ~amr_prot) {
+ srr1 |= SRR1_IAMR; /* Access violates virt pg class key prot */
+ }
+ ppc_hash64_set_isi(cs, env, srr1);
} else {
- dsisr = 0;
+ int dsisr = 0;
if (need_prot[rwx] & ~pp_prot) {
- dsisr |= 0x08000000;
+ dsisr |= DSISR_PROTFAULT;
}
if (rwx == 1) {
- dsisr |= 0x02000000;
+ dsisr |= DSISR_ISSTORE;
}
if (need_prot[rwx] & ~amr_prot) {
- dsisr |= 0x00200000;
+ dsisr |= DSISR_AMR;
}
ppc_hash64_set_dsi(cs, env, eaddr, dsisr);
}
@@ -979,8 +1032,8 @@ void helper_store_lpcr(CPUPPCState *env, target_ulong val)
uint64_t lpcr = 0;
/* Filter out bits */
- switch (env->mmu_model) {
- case POWERPC_MMU_64B: /* 970 */
+ switch (POWERPC_MMU_VER(env->mmu_model)) {
+ case POWERPC_MMU_VER_64B: /* 970 */
if (val & 0x40) {
lpcr |= LPCR_LPES0;
}
@@ -1006,26 +1059,26 @@ void helper_store_lpcr(CPUPPCState *env, target_ulong val)
* to dig HRMOR out of HID5
*/
break;
- case POWERPC_MMU_2_03: /* P5p */
+ case POWERPC_MMU_VER_2_03: /* P5p */
lpcr = val & (LPCR_RMLS | LPCR_ILE |
LPCR_LPES0 | LPCR_LPES1 |
LPCR_RMI | LPCR_HDICE);
break;
- case POWERPC_MMU_2_06: /* P7 */
+ case POWERPC_MMU_VER_2_06: /* P7 */
lpcr = val & (LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_DPFD |
LPCR_VRMASD | LPCR_RMLS | LPCR_ILE |
LPCR_P7_PECE0 | LPCR_P7_PECE1 | LPCR_P7_PECE2 |
LPCR_MER | LPCR_TC |
LPCR_LPES0 | LPCR_LPES1 | LPCR_HDICE);
break;
- case POWERPC_MMU_2_07: /* P8 */
+ case POWERPC_MMU_VER_2_07: /* P8 */
lpcr = val & (LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_KBV |
LPCR_DPFD | LPCR_VRMASD | LPCR_RMLS | LPCR_ILE |
LPCR_AIL | LPCR_ONL | LPCR_P8_PECE0 | LPCR_P8_PECE1 |
LPCR_P8_PECE2 | LPCR_P8_PECE3 | LPCR_P8_PECE4 |
LPCR_MER | LPCR_TC | LPCR_LPES0 | LPCR_HDICE);
break;
- case POWERPC_MMU_3_00: /* P9 */
+ case POWERPC_MMU_VER_3_00: /* P9 */
lpcr = val & (LPCR_VPM1 | LPCR_ISL | LPCR_KBV | LPCR_DPFD |
(LPCR_PECE_U_MASK & LPCR_HVEE) | LPCR_ILE | LPCR_AIL |
LPCR_UPRT | LPCR_EVIRT | LPCR_ONL |
diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c
index a1af3d6bf2..65d1c8692d 100644
--- a/target/ppc/mmu_helper.c
+++ b/target/ppc/mmu_helper.c
@@ -29,6 +29,7 @@
#include "exec/log.h"
#include "helper_regs.h"
#include "qemu/error-report.h"
+#include "mmu-book3s-v3.h"
//#define DEBUG_MMU
//#define DEBUG_BATS
@@ -1265,7 +1266,7 @@ static void mmu6xx_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)
{
- switch (env->mmu_model) {
+ switch (POWERPC_MMU_VER(env->mmu_model)) {
case POWERPC_MMU_BOOKE:
mmubooke_dump_mmu(f, cpu_fprintf, env);
break;
@@ -1277,14 +1278,19 @@ void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)
mmu6xx_dump_mmu(f, cpu_fprintf, env);
break;
#if defined(TARGET_PPC64)
- case POWERPC_MMU_64B:
- case POWERPC_MMU_2_03:
- case POWERPC_MMU_2_06:
- case POWERPC_MMU_2_06a:
- case POWERPC_MMU_2_07:
- case POWERPC_MMU_2_07a:
+ case POWERPC_MMU_VER_64B:
+ case POWERPC_MMU_VER_2_03:
+ case POWERPC_MMU_VER_2_06:
+ case POWERPC_MMU_VER_2_07:
dump_slb(f, cpu_fprintf, ppc_env_get_cpu(env));
break;
+ case POWERPC_MMU_VER_3_00:
+ if (ppc64_radix_guest(ppc_env_get_cpu(env))) {
+ /* TODO - Unsupported */
+ } else {
+ dump_slb(f, cpu_fprintf, ppc_env_get_cpu(env));
+ break;
+ }
#endif
default:
qemu_log_mask(LOG_UNIMP, "%s: unimplemented\n", __func__);
@@ -1417,15 +1423,20 @@ hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
CPUPPCState *env = &cpu->env;
mmu_ctx_t ctx;
- switch (env->mmu_model) {
+ switch (POWERPC_MMU_VER(env->mmu_model)) {
#if defined(TARGET_PPC64)
- case POWERPC_MMU_64B:
- case POWERPC_MMU_2_03:
- case POWERPC_MMU_2_06:
- case POWERPC_MMU_2_06a:
- case POWERPC_MMU_2_07:
- case POWERPC_MMU_2_07a:
+ case POWERPC_MMU_VER_64B:
+ case POWERPC_MMU_VER_2_03:
+ case POWERPC_MMU_VER_2_06:
+ case POWERPC_MMU_VER_2_07:
return ppc_hash64_get_phys_page_debug(cpu, addr);
+ case POWERPC_MMU_VER_3_00:
+ if (ppc64_radix_guest(ppc_env_get_cpu(env))) {
+ /* TODO - Unsupported */
+ } else {
+ return ppc_hash64_get_phys_page_debug(cpu, addr);
+ }
+ break;
#endif
case POWERPC_MMU_32B:
@@ -1909,6 +1920,12 @@ void ppc_tlb_invalidate_all(CPUPPCState *env)
{
PowerPCCPU *cpu = ppc_env_get_cpu(env);
+#if defined(TARGET_PPC64)
+ if (env->mmu_model & POWERPC_MMU_64) {
+ env->tlb_need_flush = 0;
+ tlb_flush(CPU(cpu));
+ } else
+#endif /* defined(TARGET_PPC64) */
switch (env->mmu_model) {
case POWERPC_MMU_SOFT_6xx:
case POWERPC_MMU_SOFT_74xx:
@@ -1933,21 +1950,12 @@ void ppc_tlb_invalidate_all(CPUPPCState *env)
break;
case POWERPC_MMU_32B:
case POWERPC_MMU_601:
-#if defined(TARGET_PPC64)
- case POWERPC_MMU_64B:
- case POWERPC_MMU_2_03:
- case POWERPC_MMU_2_06:
- case POWERPC_MMU_2_06a:
- case POWERPC_MMU_2_07:
- case POWERPC_MMU_2_07a:
- case POWERPC_MMU_3_00:
-#endif /* defined(TARGET_PPC64) */
env->tlb_need_flush = 0;
tlb_flush(CPU(cpu));
break;
default:
/* XXX: TODO */
- cpu_abort(CPU(cpu), "Unknown MMU model %d\n", env->mmu_model);
+ cpu_abort(CPU(cpu), "Unknown MMU model %x\n", env->mmu_model);
break;
}
}
@@ -1956,6 +1964,16 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
{
#if !defined(FLUSH_ALL_TLBS)
addr &= TARGET_PAGE_MASK;
+#if defined(TARGET_PPC64)
+ if (env->mmu_model & POWERPC_MMU_64) {
+ /* tlbie invalidate TLBs for all segments */
+ /* XXX: given the fact that there are too many segments to invalidate,
+ * and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
+ * we just invalidate all TLBs
+ */
+ env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
+ } else
+#endif /* defined(TARGET_PPC64) */
switch (env->mmu_model) {
case POWERPC_MMU_SOFT_6xx:
case POWERPC_MMU_SOFT_74xx:
@@ -1973,22 +1991,6 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
*/
env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
break;
-#if defined(TARGET_PPC64)
- case POWERPC_MMU_64B:
- case POWERPC_MMU_2_03:
- case POWERPC_MMU_2_06:
- case POWERPC_MMU_2_06a:
- case POWERPC_MMU_2_07:
- case POWERPC_MMU_2_07a:
- case POWERPC_MMU_3_00:
- /* tlbie invalidate TLBs for all segments */
- /* XXX: given the fact that there are too many segments to invalidate,
- * and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
- * we just invalidate all TLBs
- */
- env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
- break;
-#endif /* defined(TARGET_PPC64) */
default:
/* Should never reach here with other MMU models */
assert(0);
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 6e6868b7a0..b6abc60a00 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -7078,21 +7078,22 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
if (env->spr_cb[SPR_LPCR].name)
cpu_fprintf(f, " LPCR " TARGET_FMT_lx "\n", env->spr[SPR_LPCR]);
- switch (env->mmu_model) {
+ switch (POWERPC_MMU_VER(env->mmu_model)) {
case POWERPC_MMU_32B:
case POWERPC_MMU_601:
case POWERPC_MMU_SOFT_6xx:
case POWERPC_MMU_SOFT_74xx:
#if defined(TARGET_PPC64)
- case POWERPC_MMU_64B:
- case POWERPC_MMU_2_03:
- case POWERPC_MMU_2_06:
- case POWERPC_MMU_2_06a:
- case POWERPC_MMU_2_07:
- case POWERPC_MMU_2_07a:
+ case POWERPC_MMU_VER_64B:
+ case POWERPC_MMU_VER_2_03:
+ case POWERPC_MMU_VER_2_06:
+ case POWERPC_MMU_VER_2_07:
+ case POWERPC_MMU_VER_3_00:
#endif
- cpu_fprintf(f, " SDR1 " TARGET_FMT_lx " DAR " TARGET_FMT_lx
- " DSISR " TARGET_FMT_lx "\n", env->spr[SPR_SDR1],
+ if (env->spr_cb[SPR_SDR1].name) { /* SDR1 Exists */
+ cpu_fprintf(f, " SDR1 " TARGET_FMT_lx " ", env->spr[SPR_SDR1]);
+ }
+ cpu_fprintf(f, " DAR " TARGET_FMT_lx " DSISR " TARGET_FMT_lx "\n",
env->spr[SPR_DAR], env->spr[SPR_DSISR]);
break;
case POWERPC_MMU_BOOKE206:
diff --git a/target/ppc/translate_init.c b/target/ppc/translate_init.c
index 37f74be984..c1a901455c 100644
--- a/target/ppc/translate_init.c
+++ b/target/ppc/translate_init.c
@@ -32,6 +32,7 @@
#include "qapi/visitor.h"
#include "hw/qdev-properties.h"
#include "hw/ppc/ppc.h"
+#include "mmu-book3s-v3.h"
//#define PPC_DUMP_CPU
//#define PPC_DEBUG_SPR
@@ -723,7 +724,7 @@ static void gen_spr_generic (CPUPPCState *env)
}
/* SPR common to all non-embedded PowerPC, including 601 */
-static void gen_spr_ne_601 (CPUPPCState *env)
+static void gen_spr_ne_601(CPUPPCState *env)
{
/* Exception processing */
spr_register_kvm(env, SPR_DSISR, "DSISR",
@@ -739,7 +740,11 @@ static void gen_spr_ne_601 (CPUPPCState *env)
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_decr, &spr_write_decr,
0x00000000);
- /* Memory management */
+}
+
+/* Storage Description Register 1 */
+static void gen_spr_sdr1(CPUPPCState *env)
+{
#ifndef CONFIG_USER_ONLY
if (env->has_hv_mode) {
/* SDR1 is a hypervisor resource on CPUs which have a
@@ -1180,7 +1185,7 @@ static void spr_write_iamr(DisasContext *ctx, int sprn, int gprn)
}
#endif /* CONFIG_USER_ONLY */
-static void gen_spr_amr(CPUPPCState *env, bool has_iamr)
+static void gen_spr_amr(CPUPPCState *env)
{
#ifndef CONFIG_USER_ONLY
/* Virtual Page Class Key protection */
@@ -1206,13 +1211,17 @@ static void gen_spr_amr(CPUPPCState *env, bool has_iamr)
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0);
- if (has_iamr) {
- spr_register_kvm_hv(env, SPR_IAMR, "IAMR",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_iamr,
- &spr_read_generic, &spr_write_generic,
- KVM_REG_PPC_IAMR, 0);
- }
+#endif /* !CONFIG_USER_ONLY */
+}
+
+static void gen_spr_iamr(CPUPPCState *env)
+{
+#ifndef CONFIG_USER_ONLY
+ spr_register_kvm_hv(env, SPR_IAMR, "IAMR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_iamr,
+ &spr_read_generic, &spr_write_generic,
+ KVM_REG_PPC_IAMR, 0);
#endif /* !CONFIG_USER_ONLY */
}
#endif /* TARGET_PPC64 */
@@ -4422,6 +4431,7 @@ POWERPC_FAMILY(MPC8xx)(ObjectClass *oc, void *data)
static void init_proc_G2 (CPUPPCState *env)
{
gen_spr_ne_601(env);
+ gen_spr_sdr1(env);
gen_spr_G2_755(env);
gen_spr_G2(env);
/* Time base */
@@ -4500,6 +4510,7 @@ POWERPC_FAMILY(G2)(ObjectClass *oc, void *data)
static void init_proc_G2LE (CPUPPCState *env)
{
gen_spr_ne_601(env);
+ gen_spr_sdr1(env);
gen_spr_G2_755(env);
gen_spr_G2(env);
/* Time base */
@@ -4735,6 +4746,7 @@ POWERPC_FAMILY(e200)(ObjectClass *oc, void *data)
static void init_proc_e300 (CPUPPCState *env)
{
gen_spr_ne_601(env);
+ gen_spr_sdr1(env);
gen_spr_603(env);
/* Time base */
gen_tbl(env);
@@ -5234,6 +5246,7 @@ POWERPC_FAMILY(e5500)(ObjectClass *oc, void *data)
static void init_proc_601 (CPUPPCState *env)
{
gen_spr_ne_601(env);
+ gen_spr_sdr1(env);
gen_spr_601(env);
/* Hardware implementation registers */
/* XXX : not implemented */
@@ -5348,6 +5361,7 @@ POWERPC_FAMILY(601v)(ObjectClass *oc, void *data)
static void init_proc_602 (CPUPPCState *env)
{
gen_spr_ne_601(env);
+ gen_spr_sdr1(env);
gen_spr_602(env);
/* Time base */
gen_tbl(env);
@@ -5417,6 +5431,7 @@ POWERPC_FAMILY(602)(ObjectClass *oc, void *data)
static void init_proc_603 (CPUPPCState *env)
{
gen_spr_ne_601(env);
+ gen_spr_sdr1(env);
gen_spr_603(env);
/* Time base */
gen_tbl(env);
@@ -5483,6 +5498,7 @@ POWERPC_FAMILY(603)(ObjectClass *oc, void *data)
static void init_proc_603E (CPUPPCState *env)
{
gen_spr_ne_601(env);
+ gen_spr_sdr1(env);
gen_spr_603(env);
/* Time base */
gen_tbl(env);
@@ -5549,6 +5565,7 @@ POWERPC_FAMILY(603E)(ObjectClass *oc, void *data)
static void init_proc_604 (CPUPPCState *env)
{
gen_spr_ne_601(env);
+ gen_spr_sdr1(env);
gen_spr_604(env);
/* Time base */
gen_tbl(env);
@@ -5612,6 +5629,7 @@ POWERPC_FAMILY(604)(ObjectClass *oc, void *data)
static void init_proc_604E (CPUPPCState *env)
{
gen_spr_ne_601(env);
+ gen_spr_sdr1(env);
gen_spr_604(env);
/* XXX : not implemented */
spr_register(env, SPR_7XX_MMCR1, "MMCR1",
@@ -5695,6 +5713,7 @@ POWERPC_FAMILY(604E)(ObjectClass *oc, void *data)
static void init_proc_740 (CPUPPCState *env)
{
gen_spr_ne_601(env);
+ gen_spr_sdr1(env);
gen_spr_7xx(env);
/* Time base */
gen_tbl(env);
@@ -5765,6 +5784,7 @@ POWERPC_FAMILY(740)(ObjectClass *oc, void *data)
static void init_proc_750 (CPUPPCState *env)
{
gen_spr_ne_601(env);
+ gen_spr_sdr1(env);
gen_spr_7xx(env);
/* XXX : not implemented */
spr_register(env, SPR_L2CR, "L2CR",
@@ -5843,6 +5863,7 @@ POWERPC_FAMILY(750)(ObjectClass *oc, void *data)
static void init_proc_750cl (CPUPPCState *env)
{
gen_spr_ne_601(env);
+ gen_spr_sdr1(env);
gen_spr_7xx(env);
/* XXX : not implemented */
spr_register(env, SPR_L2CR, "L2CR",
@@ -6044,6 +6065,7 @@ POWERPC_FAMILY(750cl)(ObjectClass *oc, void *data)
static void init_proc_750cx (CPUPPCState *env)
{
gen_spr_ne_601(env);
+ gen_spr_sdr1(env);
gen_spr_7xx(env);
/* XXX : not implemented */
spr_register(env, SPR_L2CR, "L2CR",
@@ -6126,6 +6148,7 @@ POWERPC_FAMILY(750cx)(ObjectClass *oc, void *data)
static void init_proc_750fx (CPUPPCState *env)
{
gen_spr_ne_601(env);
+ gen_spr_sdr1(env);
gen_spr_7xx(env);
/* XXX : not implemented */
spr_register(env, SPR_L2CR, "L2CR",
@@ -6213,6 +6236,7 @@ POWERPC_FAMILY(750fx)(ObjectClass *oc, void *data)
static void init_proc_750gx (CPUPPCState *env)
{
gen_spr_ne_601(env);
+ gen_spr_sdr1(env);
gen_spr_7xx(env);
/* XXX : not implemented (XXX: different from 750fx) */
spr_register(env, SPR_L2CR, "L2CR",
@@ -6300,6 +6324,7 @@ POWERPC_FAMILY(750gx)(ObjectClass *oc, void *data)
static void init_proc_745 (CPUPPCState *env)
{
gen_spr_ne_601(env);
+ gen_spr_sdr1(env);
gen_spr_7xx(env);
gen_spr_G2_755(env);
/* Time base */
@@ -6375,6 +6400,7 @@ POWERPC_FAMILY(745)(ObjectClass *oc, void *data)
static void init_proc_755 (CPUPPCState *env)
{
gen_spr_ne_601(env);
+ gen_spr_sdr1(env);
gen_spr_7xx(env);
gen_spr_G2_755(env);
/* Time base */
@@ -6461,6 +6487,7 @@ POWERPC_FAMILY(755)(ObjectClass *oc, void *data)
static void init_proc_7400 (CPUPPCState *env)
{
gen_spr_ne_601(env);
+ gen_spr_sdr1(env);
gen_spr_7xx(env);
/* Time base */
gen_tbl(env);
@@ -6539,6 +6566,7 @@ POWERPC_FAMILY(7400)(ObjectClass *oc, void *data)
static void init_proc_7410 (CPUPPCState *env)
{
gen_spr_ne_601(env);
+ gen_spr_sdr1(env);
gen_spr_7xx(env);
/* Time base */
gen_tbl(env);
@@ -6623,6 +6651,7 @@ POWERPC_FAMILY(7410)(ObjectClass *oc, void *data)
static void init_proc_7440 (CPUPPCState *env)
{
gen_spr_ne_601(env);
+ gen_spr_sdr1(env);
gen_spr_7xx(env);
/* Time base */
gen_tbl(env);
@@ -6730,6 +6759,7 @@ POWERPC_FAMILY(7440)(ObjectClass *oc, void *data)
static void init_proc_7450 (CPUPPCState *env)
{
gen_spr_ne_601(env);
+ gen_spr_sdr1(env);
gen_spr_7xx(env);
/* Time base */
gen_tbl(env);
@@ -6863,6 +6893,7 @@ POWERPC_FAMILY(7450)(ObjectClass *oc, void *data)
static void init_proc_7445 (CPUPPCState *env)
{
gen_spr_ne_601(env);
+ gen_spr_sdr1(env);
gen_spr_7xx(env);
/* Time base */
gen_tbl(env);
@@ -6999,6 +7030,7 @@ POWERPC_FAMILY(7445)(ObjectClass *oc, void *data)
static void init_proc_7455 (CPUPPCState *env)
{
gen_spr_ne_601(env);
+ gen_spr_sdr1(env);
gen_spr_7xx(env);
/* Time base */
gen_tbl(env);
@@ -7137,6 +7169,7 @@ POWERPC_FAMILY(7455)(ObjectClass *oc, void *data)
static void init_proc_7457 (CPUPPCState *env)
{
gen_spr_ne_601(env);
+ gen_spr_sdr1(env);
gen_spr_7xx(env);
/* Time base */
gen_tbl(env);
@@ -7299,6 +7332,7 @@ POWERPC_FAMILY(7457)(ObjectClass *oc, void *data)
static void init_proc_e600 (CPUPPCState *env)
{
gen_spr_ne_601(env);
+ gen_spr_sdr1(env);
gen_spr_7xx(env);
/* Time base */
gen_tbl(env);
@@ -7444,15 +7478,6 @@ POWERPC_FAMILY(e600)(ObjectClass *oc, void *data)
#define POWERPC970_HID5_INIT 0x00000000
#endif
-enum BOOK3S_CPU_TYPE {
- BOOK3S_CPU_970,
- BOOK3S_CPU_POWER5PLUS,
- BOOK3S_CPU_POWER6,
- BOOK3S_CPU_POWER7,
- BOOK3S_CPU_POWER8,
- BOOK3S_CPU_POWER9
-};
-
static void gen_fscr_facility_check(DisasContext *ctx, int facility_sprn,
int bit, int sprn, int cause)
{
@@ -7540,7 +7565,7 @@ static void gen_spr_970_hior(CPUPPCState *env)
0x00000000);
}
-static void gen_spr_book3s_common(CPUPPCState *env)
+static void gen_spr_book3s_ctrl(CPUPPCState *env)
{
spr_register(env, SPR_CTRL, "SPR_CTRL",
SPR_NOACCESS, SPR_NOACCESS,
@@ -8210,112 +8235,42 @@ static void gen_spr_power8_rpr(CPUPPCState *env)
#endif
}
-static void init_proc_book3s_64(CPUPPCState *env, int version)
+static void init_proc_book3s_common(CPUPPCState *env)
{
gen_spr_ne_601(env);
gen_tbl(env);
gen_spr_book3s_altivec(env);
gen_spr_book3s_pmu_sup(env);
gen_spr_book3s_pmu_user(env);
- gen_spr_book3s_common(env);
+ gen_spr_book3s_ctrl(env);
+}
- switch (version) {
- case BOOK3S_CPU_970:
- case BOOK3S_CPU_POWER5PLUS:
- gen_spr_970_hid(env);
- gen_spr_970_hior(env);
- gen_low_BATs(env);
- gen_spr_970_pmu_sup(env);
- gen_spr_970_pmu_user(env);
- break;
- case BOOK3S_CPU_POWER7:
- case BOOK3S_CPU_POWER8:
- case BOOK3S_CPU_POWER9:
- gen_spr_book3s_ids(env);
- gen_spr_amr(env, version >= BOOK3S_CPU_POWER8);
- gen_spr_book3s_purr(env);
- env->ci_large_pages = true;
- break;
- default:
- g_assert_not_reached();
- }
- if (version >= BOOK3S_CPU_POWER5PLUS) {
- gen_spr_power5p_common(env);
- gen_spr_power5p_lpar(env);
- gen_spr_power5p_ear(env);
- } else {
- gen_spr_970_lpar(env);
- }
- if (version == BOOK3S_CPU_970) {
- gen_spr_970_dbg(env);
- }
- if (version >= BOOK3S_CPU_POWER6) {
- gen_spr_power6_common(env);
- gen_spr_power6_dbg(env);
- }
- if (version == BOOK3S_CPU_POWER7) {
- gen_spr_power7_book4(env);
- }
- if (version >= BOOK3S_CPU_POWER8) {
- gen_spr_power8_tce_address_control(env);
- gen_spr_power8_ids(env);
- gen_spr_power8_ebb(env);
- gen_spr_power8_fscr(env);
- gen_spr_power8_pmu_sup(env);
- gen_spr_power8_pmu_user(env);
- gen_spr_power8_tm(env);
- gen_spr_power8_pspb(env);
- gen_spr_vtb(env);
- gen_spr_power8_ic(env);
- gen_spr_power8_book4(env);
- gen_spr_power8_rpr(env);
- }
- if (version < BOOK3S_CPU_POWER8) {
- gen_spr_book3s_dbg(env);
- } else {
- gen_spr_book3s_207_dbg(env);
- }
+static void init_proc_970(CPUPPCState *env)
+{
+ /* Common Registers */
+ init_proc_book3s_common(env);
+ gen_spr_sdr1(env);
+ gen_spr_book3s_dbg(env);
+
+ /* 970 Specific Registers */
+ gen_spr_970_hid(env);
+ gen_spr_970_hior(env);
+ gen_low_BATs(env);
+ gen_spr_970_pmu_sup(env);
+ gen_spr_970_pmu_user(env);
+ gen_spr_970_lpar(env);
+ gen_spr_970_dbg(env);
+
+ /* env variables */
#if !defined(CONFIG_USER_ONLY)
- switch (version) {
- case BOOK3S_CPU_970:
- case BOOK3S_CPU_POWER5PLUS:
- env->slb_nr = 64;
- break;
- case BOOK3S_CPU_POWER7:
- case BOOK3S_CPU_POWER8:
- case BOOK3S_CPU_POWER9:
- default:
- env->slb_nr = 32;
- break;
- }
+ env->slb_nr = 64;
#endif
- /* Allocate hardware IRQ controller */
- switch (version) {
- case BOOK3S_CPU_970:
- case BOOK3S_CPU_POWER5PLUS:
- init_excp_970(env);
- ppc970_irq_init(ppc_env_get_cpu(env));
- break;
- case BOOK3S_CPU_POWER7:
- init_excp_POWER7(env);
- ppcPOWER7_irq_init(ppc_env_get_cpu(env));
- break;
- case BOOK3S_CPU_POWER8:
- case BOOK3S_CPU_POWER9:
- init_excp_POWER8(env);
- ppcPOWER7_irq_init(ppc_env_get_cpu(env));
- break;
- default:
- g_assert_not_reached();
- }
-
env->dcache_line_size = 128;
env->icache_line_size = 128;
-}
-static void init_proc_970(CPUPPCState *env)
-{
- init_proc_book3s_64(env, BOOK3S_CPU_970);
+ /* Allocate hardware IRQ controller */
+ init_excp_970(env);
+ ppc970_irq_init(ppc_env_get_cpu(env));
}
POWERPC_FAMILY(970)(ObjectClass *oc, void *data)
@@ -8367,7 +8322,31 @@ POWERPC_FAMILY(970)(ObjectClass *oc, void *data)
static void init_proc_power5plus(CPUPPCState *env)
{
- init_proc_book3s_64(env, BOOK3S_CPU_POWER5PLUS);
+ /* Common Registers */
+ init_proc_book3s_common(env);
+ gen_spr_sdr1(env);
+ gen_spr_book3s_dbg(env);
+
+ /* POWER5+ Specific Registers */
+ gen_spr_970_hid(env);
+ gen_spr_970_hior(env);
+ gen_low_BATs(env);
+ gen_spr_970_pmu_sup(env);
+ gen_spr_970_pmu_user(env);
+ gen_spr_power5p_common(env);
+ gen_spr_power5p_lpar(env);
+ gen_spr_power5p_ear(env);
+
+ /* env variables */
+#if !defined(CONFIG_USER_ONLY)
+ env->slb_nr = 64;
+#endif
+ env->dcache_line_size = 128;
+ env->icache_line_size = 128;
+
+ /* Allocate hardware IRQ controller */
+ init_excp_970(env);
+ ppc970_irq_init(ppc_env_get_cpu(env));
}
POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data)
@@ -8520,7 +8499,33 @@ static const struct ppc_segment_page_sizes POWER7_POWER8_sps = {
static void init_proc_POWER7 (CPUPPCState *env)
{
- init_proc_book3s_64(env, BOOK3S_CPU_POWER7);
+ /* Common Registers */
+ init_proc_book3s_common(env);
+ gen_spr_sdr1(env);
+ gen_spr_book3s_dbg(env);
+
+ /* POWER7 Specific Registers */
+ gen_spr_book3s_ids(env);
+ gen_spr_amr(env);
+ gen_spr_book3s_purr(env);
+ gen_spr_power5p_common(env);
+ gen_spr_power5p_lpar(env);
+ gen_spr_power5p_ear(env);
+ gen_spr_power6_common(env);
+ gen_spr_power6_dbg(env);
+ gen_spr_power7_book4(env);
+
+ /* env variables */
+#if !defined(CONFIG_USER_ONLY)
+ env->slb_nr = 32;
+#endif
+ env->ci_large_pages = true;
+ env->dcache_line_size = 128;
+ env->icache_line_size = 128;
+
+ /* Allocate hardware IRQ controller */
+ init_excp_POWER7(env);
+ ppcPOWER7_irq_init(ppc_env_get_cpu(env));
}
static bool ppc_pvr_match_power7(PowerPCCPUClass *pcc, uint32_t pvr)
@@ -8636,7 +8641,45 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
static void init_proc_POWER8(CPUPPCState *env)
{
- init_proc_book3s_64(env, BOOK3S_CPU_POWER8);
+ /* Common Registers */
+ init_proc_book3s_common(env);
+ gen_spr_sdr1(env);
+ gen_spr_book3s_207_dbg(env);
+
+ /* POWER8 Specific Registers */
+ gen_spr_book3s_ids(env);
+ gen_spr_amr(env);
+ gen_spr_iamr(env);
+ gen_spr_book3s_purr(env);
+ gen_spr_power5p_common(env);
+ gen_spr_power5p_lpar(env);
+ gen_spr_power5p_ear(env);
+ gen_spr_power6_common(env);
+ gen_spr_power6_dbg(env);
+ gen_spr_power8_tce_address_control(env);
+ gen_spr_power8_ids(env);
+ gen_spr_power8_ebb(env);
+ gen_spr_power8_fscr(env);
+ gen_spr_power8_pmu_sup(env);
+ gen_spr_power8_pmu_user(env);
+ gen_spr_power8_tm(env);
+ gen_spr_power8_pspb(env);
+ gen_spr_vtb(env);
+ gen_spr_power8_ic(env);
+ gen_spr_power8_book4(env);
+ gen_spr_power8_rpr(env);
+
+ /* env variables */
+#if !defined(CONFIG_USER_ONLY)
+ env->slb_nr = 32;
+#endif
+ env->ci_large_pages = true;
+ env->dcache_line_size = 128;
+ env->icache_line_size = 128;
+
+ /* Allocate hardware IRQ controller */
+ init_excp_POWER8(env);
+ ppcPOWER7_irq_init(ppc_env_get_cpu(env));
}
static bool ppc_pvr_match_power8(PowerPCCPUClass *pcc, uint32_t pvr)
@@ -8764,9 +8807,47 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
pcc->l1_icache_size = 0x8000;
pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr;
}
+
static void init_proc_POWER9(CPUPPCState *env)
{
- init_proc_book3s_64(env, BOOK3S_CPU_POWER9);
+ /* Common Registers */
+ init_proc_book3s_common(env);
+ gen_spr_book3s_207_dbg(env);
+
+ /* POWER8 Specific Registers */
+ gen_spr_book3s_ids(env);
+ gen_spr_amr(env);
+ gen_spr_iamr(env);
+ gen_spr_book3s_purr(env);
+ gen_spr_power5p_common(env);
+ gen_spr_power5p_lpar(env);
+ gen_spr_power5p_ear(env);
+ gen_spr_power6_common(env);
+ gen_spr_power6_dbg(env);
+ gen_spr_power8_tce_address_control(env);
+ gen_spr_power8_ids(env);
+ gen_spr_power8_ebb(env);
+ gen_spr_power8_fscr(env);
+ gen_spr_power8_pmu_sup(env);
+ gen_spr_power8_pmu_user(env);
+ gen_spr_power8_tm(env);
+ gen_spr_power8_pspb(env);
+ gen_spr_vtb(env);
+ gen_spr_power8_ic(env);
+ gen_spr_power8_book4(env);
+ gen_spr_power8_rpr(env);
+
+ /* env variables */
+#if !defined(CONFIG_USER_ONLY)
+ env->slb_nr = 32;
+#endif
+ env->ci_large_pages = true;
+ env->dcache_line_size = 128;
+ env->icache_line_size = 128;
+
+ /* Allocate hardware IRQ controller */
+ init_excp_POWER8(env);
+ ppcPOWER7_irq_init(ppc_env_get_cpu(env));
}
static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, uint32_t pvr)
@@ -8777,10 +8858,54 @@ static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, uint32_t pvr)
return false;
}
+static bool cpu_has_work_POWER9(CPUState *cs)
+{
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
+
+ if (cs->halted) {
+ if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
+ return false;
+ }
+ /* External Exception */
+ if ((env->pending_interrupts & (1u << PPC_INTERRUPT_EXT)) &&
+ (env->spr[SPR_LPCR] & LPCR_EEE)) {
+ return true;
+ }
+ /* Decrementer Exception */
+ if ((env->pending_interrupts & (1u << PPC_INTERRUPT_DECR)) &&
+ (env->spr[SPR_LPCR] & LPCR_DEE)) {
+ return true;
+ }
+ /* Machine Check or Hypervisor Maintenance Exception */
+ if ((env->pending_interrupts & (1u << PPC_INTERRUPT_MCK |
+ 1u << PPC_INTERRUPT_HMI)) && (env->spr[SPR_LPCR] & LPCR_OEE)) {
+ return true;
+ }
+ /* Privileged Doorbell Exception */
+ if ((env->pending_interrupts & (1u << PPC_INTERRUPT_DOORBELL)) &&
+ (env->spr[SPR_LPCR] & LPCR_PDEE)) {
+ return true;
+ }
+ /* Hypervisor Doorbell Exception */
+ if ((env->pending_interrupts & (1u << PPC_INTERRUPT_HDOORBELL)) &&
+ (env->spr[SPR_LPCR] & LPCR_HDEE)) {
+ return true;
+ }
+ if (env->pending_interrupts & (1u << PPC_INTERRUPT_RESET)) {
+ return true;
+ }
+ return false;
+ } else {
+ return msr_ee && (cs->interrupt_request & CPU_INTERRUPT_HARD);
+ }
+}
+
POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
+ CPUClass *cc = CPU_CLASS(oc);
dc->fw_name = "PowerPC,POWER9";
dc->desc = "POWER9";
@@ -8791,6 +8916,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
PCR_COMPAT_2_05;
pcc->init_proc = init_proc_POWER9;
pcc->check_pow = check_pow_nocheck;
+ cc->has_work = cpu_has_work_POWER9;
pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@@ -8830,7 +8956,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
(1ull << MSR_LE);
pcc->mmu_model = POWERPC_MMU_3_00;
#if defined(CONFIG_SOFTMMU)
- pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
+ pcc->handle_mmu_fault = ppc64_v3_handle_mmu_fault;
/* segment page size remain the same */
pcc->sps = &POWER7_POWER8_sps;
#endif