diff options
Diffstat (limited to 'target')
-rw-r--r-- | target/ppc/Makefile.objs | 2 | ||||
-rw-r--r-- | target/ppc/compat.c | 16 | ||||
-rw-r--r-- | target/ppc/cpu-qom.h | 16 | ||||
-rw-r--r-- | target/ppc/cpu.h | 17 | ||||
-rw-r--r-- | target/ppc/fpu_helper.c | 213 | ||||
-rw-r--r-- | target/ppc/kvm.c | 117 | ||||
-rw-r--r-- | target/ppc/mmu-book3s-v3.c | 37 | ||||
-rw-r--r-- | target/ppc/mmu-book3s-v3.h | 50 | ||||
-rw-r--r-- | target/ppc/mmu-hash64.c | 117 | ||||
-rw-r--r-- | target/ppc/mmu_helper.c | 82 | ||||
-rw-r--r-- | target/ppc/translate.c | 19 | ||||
-rw-r--r-- | target/ppc/translate_init.c | 364 |
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 |