From d29811806067de1516c2f94c0a81885fe2076fc8 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 28 Aug 2014 19:14:59 +0200 Subject: [PATCH 01/34] ppc: fix monitor access to CR This was off-by-one. Signed-off-by: Paolo Bonzini Reviewed-by: Tom Musta Signed-off-by: Alexander Graf --- monitor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monitor.c b/monitor.c index 1fc201ae82..905d8cf4d4 100644 --- a/monitor.c +++ b/monitor.c @@ -2968,7 +2968,7 @@ static target_long monitor_get_ccr (const struct MonitorDef *md, int val) u = 0; for (i = 0; i < 8; i++) - u |= env->crf[i] << (32 - (4 * i)); + u |= env->crf[i] << (32 - (4 * (i + 1))); return u; } From 72189ea41d3a9748ffc740a3af1b98abc551aa09 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 28 Aug 2014 19:15:02 +0200 Subject: [PATCH 02/34] ppc: use CRF_* in int_helper.c Signed-off-by: Paolo Bonzini Reviewed-by: Tom Musta Tested-by: Tom Musta Signed-off-by: Alexander Graf --- target-ppc/int_helper.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index 713d777076..29ff4f6e4e 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -2286,25 +2286,25 @@ uint32_t helper_bcdadd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps) if (sgna == sgnb) { result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgna, ps); zero = bcd_add_mag(&result, a, b, &invalid, &overflow); - cr = (sgna > 0) ? 4 : 8; + cr = (sgna > 0) ? 1 << CRF_GT : 1 << CRF_LT; } else if (bcd_cmp_mag(a, b) > 0) { result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgna, ps); zero = bcd_sub_mag(&result, a, b, &invalid, &overflow); - cr = (sgna > 0) ? 4 : 8; + cr = (sgna > 0) ? 1 << CRF_GT : 1 << CRF_LT; } else { result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgnb, ps); zero = bcd_sub_mag(&result, b, a, &invalid, &overflow); - cr = (sgnb > 0) ? 4 : 8; + cr = (sgnb > 0) ? 1 << CRF_GT : 1 << CRF_LT; } } if (unlikely(invalid)) { result.u64[HI_IDX] = result.u64[LO_IDX] = -1; - cr = 1; + cr = 1 << CRF_SO; } else if (overflow) { - cr |= 1; + cr |= 1 << CRF_SO; } else if (zero) { - cr = 2; + cr = 1 << CRF_EQ; } *r = result; From ebbd8b40a9f8dcc9ff048c2ce82a6219e4e80d38 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 28 Aug 2014 19:15:03 +0200 Subject: [PATCH 03/34] ppc: fix result of DLMZB when no zero bytes are found It must return 8 and place 8 in XER, but the current code uses i directly which is 9 at this point of the code. Signed-off-by: Paolo Bonzini Reviewed-by: Tom Musta Signed-off-by: Alexander Graf --- target-ppc/int_helper.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index 29ff4f6e4e..83c1ad0654 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -2556,6 +2556,7 @@ target_ulong helper_dlmzb(CPUPPCState *env, target_ulong high, } i++; } + i = 8; if (update_Rc) { env->crf[0] = 0x2; } From e57d02022c4ba748fa6c0916319f9108c4502cb9 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 28 Aug 2014 19:15:07 +0200 Subject: [PATCH 04/34] ppc: rename gen_set_cr6_from_fpscr It sets CR1, not CR6 (and the spec agrees). Signed-off-by: Paolo Bonzini Reviewed-by: Tom Musta Tested-by: Tom Musta Signed-off-by: Alexander Graf --- target-ppc/translate.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index d03daeaa48..d1deba7587 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -8221,7 +8221,7 @@ static inline TCGv_ptr gen_fprp_ptr(int reg) } #if defined(TARGET_PPC64) -static void gen_set_cr6_from_fpscr(DisasContext *ctx) +static void gen_set_cr1_from_fpscr(DisasContext *ctx) { TCGv_i32 tmp = tcg_temp_new_i32(); tcg_gen_trunc_tl_i32(tmp, cpu_fpscr); @@ -8229,7 +8229,7 @@ static void gen_set_cr6_from_fpscr(DisasContext *ctx) tcg_temp_free_i32(tmp); } #else -static void gen_set_cr6_from_fpscr(DisasContext *ctx) +static void gen_set_cr1_from_fpscr(DisasContext *ctx) { tcg_gen_shri_tl(cpu_crf[1], cpu_fpscr, 28); } @@ -8249,7 +8249,7 @@ static void gen_##name(DisasContext *ctx) \ rb = gen_fprp_ptr(rB(ctx->opcode)); \ gen_helper_##name(cpu_env, rd, ra, rb); \ if (unlikely(Rc(ctx->opcode) != 0)) { \ - gen_set_cr6_from_fpscr(ctx); \ + gen_set_cr1_from_fpscr(ctx); \ } \ tcg_temp_free_ptr(rd); \ tcg_temp_free_ptr(ra); \ @@ -8307,7 +8307,7 @@ static void gen_##name(DisasContext *ctx) \ u32_2 = tcg_const_i32(u32f2(ctx->opcode)); \ gen_helper_##name(cpu_env, rt, rb, u32_1, u32_2); \ if (unlikely(Rc(ctx->opcode) != 0)) { \ - gen_set_cr6_from_fpscr(ctx); \ + gen_set_cr1_from_fpscr(ctx); \ } \ tcg_temp_free_ptr(rt); \ tcg_temp_free_ptr(rb); \ @@ -8331,7 +8331,7 @@ static void gen_##name(DisasContext *ctx) \ i32 = tcg_const_i32(i32fld(ctx->opcode)); \ gen_helper_##name(cpu_env, rt, ra, rb, i32); \ if (unlikely(Rc(ctx->opcode) != 0)) { \ - gen_set_cr6_from_fpscr(ctx); \ + gen_set_cr1_from_fpscr(ctx); \ } \ tcg_temp_free_ptr(rt); \ tcg_temp_free_ptr(rb); \ @@ -8352,7 +8352,7 @@ static void gen_##name(DisasContext *ctx) \ rb = gen_fprp_ptr(rB(ctx->opcode)); \ gen_helper_##name(cpu_env, rt, rb); \ if (unlikely(Rc(ctx->opcode) != 0)) { \ - gen_set_cr6_from_fpscr(ctx); \ + gen_set_cr1_from_fpscr(ctx); \ } \ tcg_temp_free_ptr(rt); \ tcg_temp_free_ptr(rb); \ @@ -8373,7 +8373,7 @@ static void gen_##name(DisasContext *ctx) \ i32 = tcg_const_i32(i32fld(ctx->opcode)); \ gen_helper_##name(cpu_env, rt, rs, i32); \ if (unlikely(Rc(ctx->opcode) != 0)) { \ - gen_set_cr6_from_fpscr(ctx); \ + gen_set_cr1_from_fpscr(ctx); \ } \ tcg_temp_free_ptr(rt); \ tcg_temp_free_ptr(rs); \ From 8f9fb7ac4915dc12c23f9ebbd65808afb780abff Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 28 Aug 2014 19:15:09 +0200 Subject: [PATCH 05/34] ppc: compute mask from BI using right shift This will match the code we use in fpu_helper.c when we flip CRF_* bit-endianness. Signed-off-by: Paolo Bonzini Reviewed-by: Tom Musta Tested-by: Tom Musta Signed-off-by: Alexander Graf --- target-ppc/translate.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index d1deba7587..ff0dc13126 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -784,7 +784,7 @@ static void gen_isel(DisasContext *ctx) l1 = gen_new_label(); l2 = gen_new_label(); - mask = 1 << (3 - (bi & 0x03)); + mask = 0x08 >> (bi & 0x03); t0 = tcg_temp_new_i32(); tcg_gen_andi_i32(t0, cpu_crf[bi >> 2], mask); tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l1); @@ -3889,7 +3889,7 @@ static inline void gen_bcond(DisasContext *ctx, int type) if ((bo & 0x10) == 0) { /* Test CR */ uint32_t bi = BI(ctx->opcode); - uint32_t mask = 1 << (3 - (bi & 0x03)); + uint32_t mask = 0x08 >> (bi & 0x03); TCGv_i32 temp = tcg_temp_new_i32(); if (bo & 0x8) { @@ -3971,7 +3971,7 @@ static void glue(gen_, name)(DisasContext *ctx) else \ tcg_gen_mov_i32(t1, cpu_crf[crbB(ctx->opcode) >> 2]); \ tcg_op(t0, t0, t1); \ - bitmask = 1 << (3 - (crbD(ctx->opcode) & 0x03)); \ + bitmask = 0x08 >> (crbD(ctx->opcode) & 0x03); \ tcg_gen_andi_i32(t0, t0, bitmask); \ tcg_gen_andi_i32(t1, cpu_crf[crbD(ctx->opcode) >> 2], ~bitmask); \ tcg_gen_or_i32(cpu_crf[crbD(ctx->opcode) >> 2], t0, t1); \ From 0b6ff57640a3d51a9738af553a05007a86df332e Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Fri, 5 Sep 2014 17:04:21 +1000 Subject: [PATCH 06/34] target-ppc: Fix kvmppc_set_compat to use negotiated cpu-version By mistake, QEMU uses the maximum compatibility level from the command line instead of the value negotiated in client-architecture-support call. This replaces @max_compat with @cpu_version. This only affects guests which do not support the host CPU. Signed-off-by: Alexey Kardashevskiy Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 33fb4cc9c3..0530b0b821 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -9137,7 +9137,7 @@ int ppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version) break; } - if (kvm_enabled() && kvmppc_set_compat(cpu, cpu->max_compat) < 0) { + if (kvm_enabled() && kvmppc_set_compat(cpu, cpu->cpu_version) < 0) { error_report("Unable to set compatibility mode in KVM"); ret = -1; } From 8412d1127664775bb4e657d51522a1c777a7e9d5 Mon Sep 17 00:00:00 2001 From: Tom Musta Date: Fri, 5 Sep 2014 11:39:05 -0500 Subject: [PATCH 07/34] target-ppc: Implement IVOR[59] By Default for Book E Adjust the IVOR mask for generic Book E implementation to support bit 59. This is consistent with the Power ISA. Signed-off-by: Tom Musta Reported-by: Pierre Mallard Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 0530b0b821..9a2e788c73 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -2786,7 +2786,7 @@ static void init_excp_BookE (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_DTLB] = 0x00000000; env->excp_vectors[POWERPC_EXCP_ITLB] = 0x00000000; env->excp_vectors[POWERPC_EXCP_DEBUG] = 0x00000000; - env->ivor_mask = 0x0000FFE0UL; + env->ivor_mask = 0x0000FFF0UL; env->ivpr_mask = 0xFFFF0000UL; /* Hardware reset vector */ env->hreset_vector = 0xFFFFFFFCUL; From 0691e8ebce51e4e3bf0c76c41d8b534e3cde47ee Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 26 Aug 2014 14:30:18 +1000 Subject: [PATCH 08/34] target-ppc: virtex-ml507 machine type should depend on CONFIG_XILINX The virtex-ml507 is a Xilinx CPU based system, and requires several sub devices which are only included with CONFIG_XILINX. Therefore, it should only be compiled if CONFIG_XILINX is set. Signed-off-by: David Gibson Reviewed-by: Peter Crosthwaite Signed-off-by: Alexander Graf --- hw/ppc/Makefile.objs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs index edd44d03e7..19d99200ae 100644 --- a/hw/ppc/Makefile.objs +++ b/hw/ppc/Makefile.objs @@ -20,4 +20,4 @@ obj-$(CONFIG_MAC) += mac_newworld.o obj-$(CONFIG_E500) += e500.o mpc8544ds.o e500plat.o obj-$(CONFIG_E500) += mpc8544_guts.o ppce500_spin.o # PowerPC 440 Xilinx ML507 reference board. -obj-y += virtex_ml507.o +obj-$(CONFIG_XILINX) += virtex_ml507.o From 4aee73623d0141c5d4ce4754fc054689fb92f0e5 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 8 Sep 2014 15:30:31 +1000 Subject: [PATCH 09/34] spapr: Cleanup machine naming conventions, and prepare for 2.2 release As of qemu-2.1, spapr/pseries, has a set of versioned machine classes to represent the machine type as it appeared to the guest in different qemu versions. This allows for safe migration of guests between current and future qemu versions. However, these are organized a bit differently from those for PC: on PC, the default plain "pc" machine type is just an alias for the most recent versioned machine type. In sPAPR, it names the base machine class from which the versioned types are derived. The PC approach is preferable; it makes it clearer which explicit version is the current one. Additionally updating the "current" machine as the base class makes it even more likely than otherwise to incorrectly alter the versioned machines' behaviour when updating the current machine. Therefore this patch changes sPAPR to the PC approach - the base class becomes abstract, and plain "pseries" becomes an alias for the most recent versioned machine class. Since qemu-2.1 is now released, we also create a new pseries-2.2 machine type, to incorporate changes during this development cycle (for now it is identical to pseries-2.1). Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/ppc/spapr.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 0a2bfe6565..2a7807578e 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1660,9 +1660,6 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc); NMIClass *nc = NMI_CLASS(oc); - mc->name = "pseries"; - mc->desc = "pSeries Logical Partition (PAPR compliant)"; - mc->is_default = 1; mc->init = ppc_spapr_init; mc->reset = ppc_spapr_reset; mc->block_default_type = IF_SCSI; @@ -1678,6 +1675,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) static const TypeInfo spapr_machine_info = { .name = TYPE_SPAPR_MACHINE, .parent = TYPE_MACHINE, + .abstract = true, .instance_size = sizeof(sPAPRMachineState), .instance_init = spapr_machine_initfn, .class_init = spapr_machine_class_init, @@ -1698,7 +1696,6 @@ static void spapr_machine_2_1_class_init(ObjectClass *oc, void *data) mc->name = "pseries-2.1"; mc->desc = "pSeries Logical Partition (PAPR compliant) v2.1"; - mc->is_default = 0; mc->compat_props = compat_props; } @@ -1708,10 +1705,27 @@ static const TypeInfo spapr_machine_2_1_info = { .class_init = spapr_machine_2_1_class_init, }; +static void spapr_machine_2_2_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->name = "pseries-2.2"; + mc->desc = "pSeries Logical Partition (PAPR compliant) v2.2"; + mc->alias = "pseries"; + mc->is_default = 1; +} + +static const TypeInfo spapr_machine_2_2_info = { + .name = TYPE_SPAPR_MACHINE "2.2", + .parent = TYPE_SPAPR_MACHINE, + .class_init = spapr_machine_2_2_class_init, +}; + static void spapr_machine_register_types(void) { type_register_static(&spapr_machine_info); type_register_static(&spapr_machine_2_1_info); + type_register_static(&spapr_machine_2_2_info); } type_init(spapr_machine_register_types) From 9ac58dc59aaf9db20ec17df9b372915bee9b0f02 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 11 Sep 2014 12:22:57 +0200 Subject: [PATCH 10/34] PPC: openpic_kvm: Only map first occurence in address space The in-kernel OpenPIC emulation only supports a single map. However, we map the OpenPIC at 2 locations: The CPU visible one and the PCI visible one. For KVM acceleration, we only care about the first one. To make sure that we only map that first mapping and not the PCI map that happens dynamically later during bootup, ignore maps that happen when we are already considering ourselves mapped. Credits due are to Bogdan and Mihai for debugging this. Reported-by: Bogdan Purcareata Reported-by: Mihai Caraman Signed-off-by: Alexander Graf --- hw/intc/openpic_kvm.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/hw/intc/openpic_kvm.c b/hw/intc/openpic_kvm.c index e3bce043a3..3e2cd189ff 100644 --- a/hw/intc/openpic_kvm.c +++ b/hw/intc/openpic_kvm.c @@ -45,6 +45,7 @@ typedef struct KVMOpenPICState { MemoryListener mem_listener; uint32_t fd; uint32_t model; + hwaddr mapped; } KVMOpenPICState; static void kvm_openpic_set_irq(void *opaque, int n_IRQ, int level) @@ -128,7 +129,16 @@ static void kvm_openpic_region_add(MemoryListener *listener, return; } + if (opp->mapped) { + /* + * We can only map the MPIC once. Since we are already mapped, + * the best we can do is ignore new maps. + */ + return; + } + reg_base = section->offset_within_address_space; + opp->mapped = reg_base; attr.group = KVM_DEV_MPIC_GRP_MISC; attr.attr = KVM_DEV_MPIC_BASE_ADDR; @@ -155,6 +165,15 @@ static void kvm_openpic_region_del(MemoryListener *listener, return; } + if (section->offset_within_address_space != opp->mapped) { + /* + * We can only map the MPIC once. This mapping was a secondary + * one that we couldn't fulfill. Ignore it. + */ + return; + } + opp->mapped = 0; + attr.group = KVM_DEV_MPIC_GRP_MISC; attr.attr = KVM_DEV_MPIC_BASE_ADDR; attr.addr = (uint64_t)(unsigned long)®_base; From 4171853cf4dfb88da93bf77a4c9d319d6ba2bdc6 Mon Sep 17 00:00:00 2001 From: Pierre Mallard Date: Fri, 12 Sep 2014 21:31:32 +0200 Subject: [PATCH 11/34] target-ppc : Allow fc[tf]id[*] mnemonics for non TARGET_PPC64 This patch remove limitation for fc[tf]id[*] on 32 bits targets and add a new insn flag for signed integer 64 conversion PPC2_FP_CVT_S64 Signed-off-by: Pierre Mallard Signed-off-by: Alexander Graf --- target-ppc/cpu.h | 5 ++++- target-ppc/fpu_helper.c | 6 ------ target-ppc/helper.h | 2 -- target-ppc/translate.c | 16 ++++++---------- target-ppc/translate_init.c | 9 ++++++--- 5 files changed, 16 insertions(+), 22 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 872456171f..f367344475 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -2007,13 +2007,16 @@ enum { PPC2_ALTIVEC_207 = 0x0000000000004000ULL, /* PowerISA 2.07 Book3s specification */ PPC2_ISA207S = 0x0000000000008000ULL, + /* Double precision floating point conversion for signed integer 64 */ + PPC2_FP_CVT_S64 = 0x0000000000010000ULL, #define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_VSX | PPC2_PRCNTL | PPC2_DBRX | \ PPC2_ISA205 | PPC2_VSX207 | PPC2_PERM_ISA206 | \ PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 | \ PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206 | \ PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | \ - PPC2_ALTIVEC_207 | PPC2_ISA207S | PPC2_DFP) + PPC2_ALTIVEC_207 | PPC2_ISA207S | PPC2_DFP | \ + PPC2_FP_CVT_S64) }; /*****************************************************************************/ diff --git a/target-ppc/fpu_helper.c b/target-ppc/fpu_helper.c index da93d1215a..7f74466f32 100644 --- a/target-ppc/fpu_helper.c +++ b/target-ppc/fpu_helper.c @@ -649,14 +649,10 @@ FPU_FCTI(fctiw, int32, 0x80000000U) FPU_FCTI(fctiwz, int32_round_to_zero, 0x80000000U) FPU_FCTI(fctiwu, uint32, 0x00000000U) FPU_FCTI(fctiwuz, uint32_round_to_zero, 0x00000000U) -#if defined(TARGET_PPC64) FPU_FCTI(fctid, int64, 0x8000000000000000ULL) FPU_FCTI(fctidz, int64_round_to_zero, 0x8000000000000000ULL) FPU_FCTI(fctidu, uint64, 0x0000000000000000ULL) FPU_FCTI(fctiduz, uint64_round_to_zero, 0x0000000000000000ULL) -#endif - -#if defined(TARGET_PPC64) #define FPU_FCFI(op, cvtr, is_single) \ uint64_t helper_##op(CPUPPCState *env, uint64_t arg) \ @@ -678,8 +674,6 @@ FPU_FCFI(fcfids, int64_to_float32, 1) FPU_FCFI(fcfidu, uint64_to_float64, 0) FPU_FCFI(fcfidus, uint64_to_float32, 1) -#endif - static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg, int rounding_mode) { diff --git a/target-ppc/helper.h b/target-ppc/helper.h index 0cfdc8ab8f..210fd97f6a 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -66,7 +66,6 @@ DEF_HELPER_2(fctiw, i64, env, i64) DEF_HELPER_2(fctiwu, i64, env, i64) DEF_HELPER_2(fctiwz, i64, env, i64) DEF_HELPER_2(fctiwuz, i64, env, i64) -#if defined(TARGET_PPC64) DEF_HELPER_2(fcfid, i64, env, i64) DEF_HELPER_2(fcfidu, i64, env, i64) DEF_HELPER_2(fcfids, i64, env, i64) @@ -75,7 +74,6 @@ DEF_HELPER_2(fctid, i64, env, i64) DEF_HELPER_2(fctidu, i64, env, i64) DEF_HELPER_2(fctidz, i64, env, i64) DEF_HELPER_2(fctiduz, i64, env, i64) -#endif DEF_HELPER_2(frsp, i64, env, i64) DEF_HELPER_2(frin, i64, env, i64) DEF_HELPER_2(friz, i64, env, i64) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index ff0dc13126..2b1fcbb5fd 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2287,9 +2287,8 @@ GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT); GEN_FLOAT_B(ctiwuz, 0x0F, 0x04, 0, PPC2_FP_CVT_ISA206); /* frsp */ GEN_FLOAT_B(rsp, 0x0C, 0x00, 1, PPC_FLOAT); -#if defined(TARGET_PPC64) /* fcfid */ -GEN_FLOAT_B(cfid, 0x0E, 0x1A, 1, PPC_64B); +GEN_FLOAT_B(cfid, 0x0E, 0x1A, 1, PPC2_FP_CVT_S64); /* fcfids */ GEN_FLOAT_B(cfids, 0x0E, 0x1A, 0, PPC2_FP_CVT_ISA206); /* fcfidu */ @@ -2297,14 +2296,13 @@ GEN_FLOAT_B(cfidu, 0x0E, 0x1E, 0, PPC2_FP_CVT_ISA206); /* fcfidus */ GEN_FLOAT_B(cfidus, 0x0E, 0x1E, 0, PPC2_FP_CVT_ISA206); /* fctid */ -GEN_FLOAT_B(ctid, 0x0E, 0x19, 0, PPC_64B); +GEN_FLOAT_B(ctid, 0x0E, 0x19, 0, PPC2_FP_CVT_S64); /* fctidu */ GEN_FLOAT_B(ctidu, 0x0E, 0x1D, 0, PPC2_FP_CVT_ISA206); /* fctidz */ -GEN_FLOAT_B(ctidz, 0x0F, 0x19, 0, PPC_64B); +GEN_FLOAT_B(ctidz, 0x0F, 0x19, 0, PPC2_FP_CVT_S64); /* fctidu */ GEN_FLOAT_B(ctiduz, 0x0F, 0x1D, 0, PPC2_FP_CVT_ISA206); -#endif /* frin */ GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT); @@ -10091,16 +10089,14 @@ GEN_HANDLER_E(fctiwu, 0x3F, 0x0E, 0x04, 0, PPC_NONE, PPC2_FP_CVT_ISA206), GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT), GEN_HANDLER_E(fctiwuz, 0x3F, 0x0F, 0x04, 0, PPC_NONE, PPC2_FP_CVT_ISA206), GEN_FLOAT_B(rsp, 0x0C, 0x00, 1, PPC_FLOAT), -#if defined(TARGET_PPC64) -GEN_FLOAT_B(cfid, 0x0E, 0x1A, 1, PPC_64B), +GEN_HANDLER_E(fcfid, 0x3F, 0x0E, 0x1A, 0x001F0000, PPC_NONE, PPC2_FP_CVT_S64), GEN_HANDLER_E(fcfids, 0x3B, 0x0E, 0x1A, 0, PPC_NONE, PPC2_FP_CVT_ISA206), GEN_HANDLER_E(fcfidu, 0x3F, 0x0E, 0x1E, 0, PPC_NONE, PPC2_FP_CVT_ISA206), GEN_HANDLER_E(fcfidus, 0x3B, 0x0E, 0x1E, 0, PPC_NONE, PPC2_FP_CVT_ISA206), -GEN_FLOAT_B(ctid, 0x0E, 0x19, 0, PPC_64B), +GEN_HANDLER_E(fctid, 0x3F, 0x0E, 0x19, 0x001F0000, PPC_NONE, PPC2_FP_CVT_S64), GEN_HANDLER_E(fctidu, 0x3F, 0x0E, 0x1D, 0, PPC_NONE, PPC2_FP_CVT_ISA206), -GEN_FLOAT_B(ctidz, 0x0F, 0x19, 0, PPC_64B), +GEN_HANDLER_E(fctidz, 0x3F, 0x0F, 0x19, 0x001F0000, PPC_NONE, PPC2_FP_CVT_S64), GEN_HANDLER_E(fctiduz, 0x3F, 0x0F, 0x1D, 0, PPC_NONE, PPC2_FP_CVT_ISA206), -#endif GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT), GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT), GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT), diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 9a2e788c73..41bd961c00 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -5010,7 +5010,8 @@ POWERPC_FAMILY(e5500)(ObjectClass *oc, void *data) PPC_FLOAT_STFIWX | PPC_WAIT | PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC | PPC_64B | PPC_POPCNTB | PPC_POPCNTWD; - pcc->insns_flags2 = PPC2_BOOKE206 | PPC2_PRCNTL | PPC2_PERM_ISA206; + pcc->insns_flags2 = PPC2_BOOKE206 | PPC2_PRCNTL | PPC2_PERM_ISA206 | \ + PPC2_FP_CVT_S64; pcc->msr_mask = (1ull << MSR_CM) | (1ull << MSR_GS) | (1ull << MSR_UCLE) | @@ -7906,6 +7907,7 @@ POWERPC_FAMILY(970)(ObjectClass *oc, void *data) PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_64B | PPC_ALTIVEC | PPC_SEGMENT_64B | PPC_SLBI; + pcc->insns_flags2 = PPC2_FP_CVT_S64; pcc->msr_mask = (1ull << MSR_SF) | (1ull << MSR_VR) | (1ull << MSR_POW) | @@ -7958,6 +7960,7 @@ POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data) PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_64B | PPC_SEGMENT_64B | PPC_SLBI; + pcc->insns_flags2 = PPC2_FP_CVT_S64; pcc->msr_mask = (1ull << MSR_SF) | (1ull << MSR_VR) | (1ull << MSR_POW) | @@ -8100,7 +8103,7 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) pcc->insns_flags2 = PPC2_VSX | PPC2_DFP | PPC2_DBRX | PPC2_ISA205 | PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 | - PPC2_FP_TST_ISA206; + PPC2_FP_TST_ISA206 | PPC2_FP_CVT_S64; pcc->msr_mask = (1ull << MSR_SF) | (1ull << MSR_VR) | (1ull << MSR_VSX) | @@ -8178,7 +8181,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206 | PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 | - PPC2_ISA205 | PPC2_ISA207S; + PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64; pcc->msr_mask = (1ull << MSR_SF) | (1ull << MSR_TM) | (1ull << MSR_VR) | From b8c867ed0961e22938c2be4903f13f46b52f84f7 Mon Sep 17 00:00:00 2001 From: Pierre Mallard Date: Fri, 12 Sep 2014 21:31:33 +0200 Subject: [PATCH 12/34] target-ppc : Add new processor type 440x5wDFPU This patch add a new processor type 440x5wDFPU for Virtex 5 PPC440 with an external APU FPU in double precision mode Signed-off-by: Pierre Mallard Signed-off-by: Alexander Graf --- target-ppc/cpu-models.c | 3 +++ target-ppc/translate_init.c | 38 +++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/target-ppc/cpu-models.c b/target-ppc/cpu-models.c index 52ac6ec156..3f18996bb0 100644 --- a/target-ppc/cpu-models.c +++ b/target-ppc/cpu-models.c @@ -309,6 +309,9 @@ #endif POWERPC_DEF("440-Xilinx", CPU_POWERPC_440_XILINX, 440x5, "PowerPC 440 Xilinx 5") + + POWERPC_DEF("440-Xilinx-w-dfpu", CPU_POWERPC_440_XILINX, 440x5wDFPU, + "PowerPC 440 Xilinx 5 With a Double Prec. FPU") #if defined(TODO) POWERPC_DEF("440A5", CPU_POWERPC_440A5, 440x5, "PowerPC 440 A5") diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 41bd961c00..8bfd55de26 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -3923,6 +3923,44 @@ POWERPC_FAMILY(440x5)(ObjectClass *oc, void *data) POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; } +POWERPC_FAMILY(440x5wDFPU)(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + dc->desc = "PowerPC 440x5 with double precision FPU"; + pcc->init_proc = init_proc_440x5; + pcc->check_pow = check_pow_nocheck; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | + PPC_FLOAT | PPC_FLOAT_FSQRT | + PPC_FLOAT_STFIWX | + PPC_DCR | PPC_WRTEE | PPC_RFMCI | + PPC_CACHE | PPC_CACHE_ICBI | + PPC_CACHE_DCBZ | PPC_CACHE_DCBA | + PPC_MEM_TLBSYNC | PPC_MFTB | + PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | + PPC_440_SPEC; + pcc->insns_flags2 = PPC2_FP_CVT_S64; + pcc->msr_mask = (1ull << MSR_POW) | + (1ull << MSR_CE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_DWE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_IR) | + (1ull << MSR_DR); + pcc->mmu_model = POWERPC_MMU_BOOKE; + pcc->excp_model = POWERPC_EXCP_BOOKE; + pcc->bus_model = PPC_FLAGS_INPUT_BookE; + pcc->bfd_mach = bfd_mach_ppc_403; + pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DWE | + POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; +} + static void init_proc_460 (CPUPPCState *env) { /* Time base */ From bf362e96106648f5dd53c7a4af4e5aed3ef09f5d Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Sun, 14 Sep 2014 20:38:47 +0100 Subject: [PATCH 13/34] hw/pci/ppc4xx_pci.c: Remove unused pci4xx_cfgaddr_read/write/ops The MemoryRegionOps struct pci4xx_cfgaddr_ops and the read and write functions it references are all unused; remove them. Signed-off-by: Peter Maydell Signed-off-by: Alexander Graf --- hw/ppc/ppc4xx_pci.c | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/hw/ppc/ppc4xx_pci.c b/hw/ppc/ppc4xx_pci.c index 55a3cabee5..0bb3cdb46e 100644 --- a/hw/ppc/ppc4xx_pci.c +++ b/hw/ppc/ppc4xx_pci.c @@ -92,30 +92,6 @@ typedef struct PPC4xxPCIState PPC4xxPCIState; #define PCI_ALL_SIZE (PCI_REG_BASE + PCI_REG_SIZE) -static uint64_t pci4xx_cfgaddr_read(void *opaque, hwaddr addr, - unsigned size) -{ - PPC4xxPCIState *ppc4xx_pci = opaque; - PCIHostState *phb = PCI_HOST_BRIDGE(ppc4xx_pci); - - return phb->config_reg; -} - -static void pci4xx_cfgaddr_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - PPC4xxPCIState *ppc4xx_pci = opaque; - PCIHostState *phb = PCI_HOST_BRIDGE(ppc4xx_pci); - - phb->config_reg = value & ~0x3; -} - -static const MemoryRegionOps pci4xx_cfgaddr_ops = { - .read = pci4xx_cfgaddr_read, - .write = pci4xx_cfgaddr_write, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - static void ppc4xx_pci_reg_write4(void *opaque, hwaddr offset, uint64_t value, unsigned size) { From 54ff58bb10acd6938b43dd3504ece4a7f4eb3fa1 Mon Sep 17 00:00:00 2001 From: Bharata B Rao Date: Fri, 26 Sep 2014 14:37:37 +0530 Subject: [PATCH 14/34] target-ppc: Use macros in opcodes table handling code Define and use macros instead of direct numbers wherever possible in ppc opcodes table handling code. This doesn't change any code functionality. Signed-off-by: Bharata B Rao Signed-off-by: Alexander Graf --- target-ppc/cpu.h | 3 ++- target-ppc/translate_init.c | 24 ++++++++++++++---------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index f367344475..068fcb24a2 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -924,7 +924,8 @@ struct ppc_segment_page_sizes { /* The whole PowerPC CPU context */ #define NB_MMU_MODES 3 -#define PPC_CPU_OPCODES_LEN 0x40 +#define PPC_CPU_OPCODES_LEN 0x40 +#define PPC_CPU_INDIRECT_OPCODES_LEN 0x20 struct CPUPPCState { /* First are the most commonly used resources diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 8bfd55de26..3ff68ae9ad 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -8473,14 +8473,16 @@ enum { PPC_INDIRECT = 1, /* Indirect opcode table */ }; +#define PPC_OPCODE_MASK 0x3 + static inline int is_indirect_opcode (void *handler) { - return ((uintptr_t)handler & 0x03) == PPC_INDIRECT; + return ((uintptr_t)handler & PPC_OPCODE_MASK) == PPC_INDIRECT; } static inline opc_handler_t **ind_table(void *handler) { - return (opc_handler_t **)((uintptr_t)handler & ~3); + return (opc_handler_t **)((uintptr_t)handler & ~PPC_OPCODE_MASK); } /* Instruction table creation */ @@ -8497,8 +8499,8 @@ static int create_new_table (opc_handler_t **table, unsigned char idx) { opc_handler_t **tmp; - tmp = g_new(opc_handler_t *, 0x20); - fill_new_table(tmp, 0x20); + tmp = g_new(opc_handler_t *, PPC_CPU_INDIRECT_OPCODES_LEN); + fill_new_table(tmp, PPC_CPU_INDIRECT_OPCODES_LEN); table[idx] = (opc_handler_t *)((uintptr_t)tmp | PPC_INDIRECT); return 0; @@ -8625,7 +8627,8 @@ static int test_opcode_table (opc_handler_t **table, int len) table[i] = &invalid_handler; if (table[i] != &invalid_handler) { if (is_indirect_opcode(table[i])) { - tmp = test_opcode_table(ind_table(table[i]), 0x20); + tmp = test_opcode_table(ind_table(table[i]), + PPC_CPU_INDIRECT_OPCODES_LEN); if (tmp == 0) { free(table[i]); table[i] = &invalid_handler; @@ -8643,7 +8646,7 @@ static int test_opcode_table (opc_handler_t **table, int len) static void fix_opcode_tables (opc_handler_t **ppc_opcodes) { - if (test_opcode_table(ppc_opcodes, 0x40) == 0) + if (test_opcode_table(ppc_opcodes, PPC_CPU_OPCODES_LEN) == 0) printf("*** WARNING: no opcode defined !\n"); } @@ -8654,7 +8657,7 @@ static void create_ppc_opcodes(PowerPCCPU *cpu, Error **errp) CPUPPCState *env = &cpu->env; opcode_t *opc; - fill_new_table(env->opcodes, 0x40); + fill_new_table(env->opcodes, PPC_CPU_OPCODES_LEN); for (opc = opcodes; opc < &opcodes[ARRAY_SIZE(opcodes)]; opc++) { if (((opc->handler.type & pcc->insns_flags) != 0) || ((opc->handler.type2 & pcc->insns_flags2) != 0)) { @@ -8680,12 +8683,12 @@ static void dump_ppc_insns (CPUPPCState *env) printf("Instructions set:\n"); /* opc1 is 6 bits long */ - for (opc1 = 0x00; opc1 < 0x40; opc1++) { + for (opc1 = 0x00; opc1 < PPC_CPU_OPCODES_LEN; opc1++) { table = env->opcodes; handler = table[opc1]; if (is_indirect_opcode(handler)) { /* opc2 is 5 bits long */ - for (opc2 = 0; opc2 < 0x20; opc2++) { + for (opc2 = 0; opc2 < PPC_CPU_INDIRECT_OPCODES_LEN; opc2++) { table = env->opcodes; handler = env->opcodes[opc1]; table = ind_table(handler); @@ -8693,7 +8696,8 @@ static void dump_ppc_insns (CPUPPCState *env) if (is_indirect_opcode(handler)) { table = ind_table(handler); /* opc3 is 5 bits long */ - for (opc3 = 0; opc3 < 0x20; opc3++) { + for (opc3 = 0; opc3 < PPC_CPU_INDIRECT_OPCODES_LEN; + opc3++) { handler = table[opc3]; if (handler->handler != &gen_invalid) { /* Special hack to properly dump SPE insns */ From 81f194dd69756677cc36ff0827bf970f0f048914 Mon Sep 17 00:00:00 2001 From: Bharata B Rao Date: Fri, 26 Sep 2014 14:37:38 +0530 Subject: [PATCH 15/34] target-ppc: Fix an invalid free in opcode table handling code. Opcode table has direct, indirect and double indirect handlers, but ppc_cpu_unrealizefn() frees direct handlers which are never allocated and never frees double indirect handlers. Signed-off-by: Bharata B Rao Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 3ff68ae9ad..20d58c01db 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -9132,11 +9132,24 @@ static void ppc_cpu_unrealizefn(DeviceState *dev, Error **errp) { PowerPCCPU *cpu = POWERPC_CPU(dev); CPUPPCState *env = &cpu->env; - int i; + opc_handler_t **table; + int i, j; for (i = 0; i < PPC_CPU_OPCODES_LEN; i++) { - if (env->opcodes[i] != &invalid_handler) { - g_free(env->opcodes[i]); + if (env->opcodes[i] == &invalid_handler) { + continue; + } + if (is_indirect_opcode(env->opcodes[i])) { + table = ind_table(env->opcodes[i]); + for (j = 0; j < PPC_CPU_INDIRECT_OPCODES_LEN; j++) { + if (table[j] != &invalid_handler && + is_indirect_opcode(table[j])) { + g_free((opc_handler_t *)((uintptr_t)table[j] & + ~PPC_INDIRECT)); + } + } + g_free((opc_handler_t *)((uintptr_t)env->opcodes[i] & + ~PPC_INDIRECT)); } } } From 228aa992fc5be408888c423b6a5b30daf18a96cf Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 1 Oct 2014 15:52:12 +0200 Subject: [PATCH 16/34] PPC: Add MPC8XXX gpio controller On e500 systems most SoCs implement a common GPIO controller that Linux calls the "mpc8xxx" gpio controller. This patch adds an emulation model for this device. Signed-off-by: Alexander Graf --- hw/gpio/Makefile.objs | 1 + hw/gpio/mpc8xxx.c | 217 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 218 insertions(+) create mode 100644 hw/gpio/mpc8xxx.c diff --git a/hw/gpio/Makefile.objs b/hw/gpio/Makefile.objs index 2c8b51f09a..1abcf17988 100644 --- a/hw/gpio/Makefile.objs +++ b/hw/gpio/Makefile.objs @@ -2,5 +2,6 @@ common-obj-$(CONFIG_MAX7310) += max7310.o common-obj-$(CONFIG_PL061) += pl061.o common-obj-$(CONFIG_PUV3) += puv3_gpio.o common-obj-$(CONFIG_ZAURUS) += zaurus.o +common-obj-$(CONFIG_E500) += mpc8xxx.o obj-$(CONFIG_OMAP) += omap_gpio.o diff --git a/hw/gpio/mpc8xxx.c b/hw/gpio/mpc8xxx.c new file mode 100644 index 0000000000..1aeaaaaf03 --- /dev/null +++ b/hw/gpio/mpc8xxx.c @@ -0,0 +1,217 @@ +/* + * GPIO Controller for a lot of Freescale SoCs + * + * Copyright (C) 2014 Freescale Semiconductor, Inc. All rights reserved. + * + * Author: Alexander Graf, + * + * 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 . + */ + +#include "hw/sysbus.h" + +#define TYPE_MPC8XXX_GPIO "mpc8xxx_gpio" +#define MPC8XXX_GPIO(obj) OBJECT_CHECK(MPC8XXXGPIOState, (obj), TYPE_MPC8XXX_GPIO) + +typedef struct MPC8XXXGPIOState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + qemu_irq irq; + qemu_irq out[32]; + + uint32_t dir; + uint32_t odr; + uint32_t dat; + uint32_t ier; + uint32_t imr; + uint32_t icr; +} MPC8XXXGPIOState; + +static const VMStateDescription vmstate_mpc8xxx_gpio = { + .name = "mpc8xxx_gpio", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(dir, MPC8XXXGPIOState), + VMSTATE_UINT32(odr, MPC8XXXGPIOState), + VMSTATE_UINT32(dat, MPC8XXXGPIOState), + VMSTATE_UINT32(ier, MPC8XXXGPIOState), + VMSTATE_UINT32(imr, MPC8XXXGPIOState), + VMSTATE_UINT32(icr, MPC8XXXGPIOState), + VMSTATE_END_OF_LIST() + } +}; + +static void mpc8xxx_gpio_update(MPC8XXXGPIOState *s) +{ + qemu_set_irq(s->irq, !!(s->ier & s->imr)); +} + +static uint64_t mpc8xxx_gpio_read(void *opaque, hwaddr offset, + unsigned size) +{ + MPC8XXXGPIOState *s = (MPC8XXXGPIOState *)opaque; + + if (size != 4) { + /* All registers are 32bit */ + return 0; + } + + switch (offset) { + case 0x0: /* Direction */ + return s->dir; + case 0x4: /* Open Drain */ + return s->odr; + case 0x8: /* Data */ + return s->dat; + case 0xC: /* Interrupt Event */ + return s->ier; + case 0x10: /* Interrupt Mask */ + return s->imr; + case 0x14: /* Interrupt Control */ + return s->icr; + default: + return 0; + } +} + +static void mpc8xxx_write_data(MPC8XXXGPIOState *s, uint32_t new_data) +{ + uint32_t old_data = s->dat; + uint32_t diff = old_data ^ new_data; + int i; + + for (i = 0; i < 32; i++) { + uint32_t mask = 0x80000000 >> i; + if (!(diff & mask)) { + continue; + } + + if (s->dir & mask) { + /* Output */ + qemu_set_irq(s->out[i], (new_data & mask) != 0); + } + } + + s->dat = new_data; +} + +static void mpc8xxx_gpio_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + MPC8XXXGPIOState *s = (MPC8XXXGPIOState *)opaque; + + if (size != 4) { + /* All registers are 32bit */ + return; + } + + switch (offset) { + case 0x0: /* Direction */ + s->dir = value; + break; + case 0x4: /* Open Drain */ + s->odr = value; + break; + case 0x8: /* Data */ + mpc8xxx_write_data(s, value); + break; + case 0xC: /* Interrupt Event */ + s->ier &= ~value; + break; + case 0x10: /* Interrupt Mask */ + s->imr = value; + break; + case 0x14: /* Interrupt Control */ + s->icr = value; + break; + } + + mpc8xxx_gpio_update(s); +} + +static void mpc8xxx_gpio_reset(MPC8XXXGPIOState *s) +{ + s->dir = 0; + s->odr = 0; + s->dat = 0; + s->ier = 0; + s->imr = 0; + s->icr = 0; +} + +static void mpc8xxx_gpio_set_irq(void * opaque, int irq, int level) +{ + MPC8XXXGPIOState *s = (MPC8XXXGPIOState *)opaque; + uint32_t mask; + + mask = 0x80000000 >> irq; + if ((s->dir & mask) == 0) { + uint32_t old_value = s->dat & mask; + + s->dat &= ~mask; + if (level) + s->dat |= mask; + + if (!(s->icr & irq) || (old_value && !level)) { + s->ier |= mask; + } + + mpc8xxx_gpio_update(s); + } +} + +static const MemoryRegionOps mpc8xxx_gpio_ops = { + .read = mpc8xxx_gpio_read, + .write = mpc8xxx_gpio_write, + .endianness = DEVICE_BIG_ENDIAN, +}; + +static int mpc8xxx_gpio_initfn(SysBusDevice *sbd) +{ + DeviceState *dev = DEVICE(sbd); + MPC8XXXGPIOState *s = MPC8XXX_GPIO(dev); + + memory_region_init_io(&s->iomem, OBJECT(s), &mpc8xxx_gpio_ops, s, "mpc8xxx_gpio", 0x1000); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); + qdev_init_gpio_in(dev, mpc8xxx_gpio_set_irq, 32); + qdev_init_gpio_out(dev, s->out, 32); + mpc8xxx_gpio_reset(s); + return 0; +} + +static void mpc8xxx_gpio_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = mpc8xxx_gpio_initfn; + dc->vmsd = &vmstate_mpc8xxx_gpio; +} + +static const TypeInfo mpc8xxx_gpio_info = { + .name = TYPE_MPC8XXX_GPIO, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(MPC8XXXGPIOState), + .class_init = mpc8xxx_gpio_class_init, +}; + +static void mpc8xxx_gpio_register_types(void) +{ + type_register_static(&mpc8xxx_gpio_info); +} + +type_init(mpc8xxx_gpio_register_types) From b88e77f49331f1187118b7ce2494ec169d3a865a Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 1 Oct 2014 16:00:49 +0200 Subject: [PATCH 17/34] PPC: E500: Instantiate MPC8XXX gpio controller on virt machine With the e500 virt machine, we don't have to adhere to the exact hardware layout of an mpc8544ds board. So there we can just add a qoriq compatible GPIO controller into the system that we can add a power off hook to. Signed-off-by: Alexander Graf --- hw/ppc/e500.c | 32 ++++++++++++++++++++++++++++++++ hw/ppc/e500.h | 1 + hw/ppc/e500plat.c | 1 + 3 files changed, 34 insertions(+) diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 2157d87c19..304c124ffd 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -61,6 +61,8 @@ #define MPC8544_PCI_IO 0xE1000000ULL #define MPC8544_UTIL_OFFSET 0xe0000ULL #define MPC8544_SPIN_BASE 0xEF000000ULL +#define MPC8XXX_GPIO_OFFSET 0x000FF000ULL +#define MPC8XXX_GPIO_IRQ 43 struct boot_info { @@ -122,6 +124,23 @@ static void dt_serial_create(void *fdt, unsigned long long offset, } } +static void create_dt_mpc8xxx_gpio(void *fdt, const char *soc, const char *mpic) +{ + hwaddr mmio0 = MPC8XXX_GPIO_OFFSET; + int irq0 = MPC8XXX_GPIO_IRQ; + gchar *node = g_strdup_printf("%s/gpio@%"PRIx64, soc, mmio0); + + qemu_fdt_add_subnode(fdt, node); + qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,qoriq-gpio"); + qemu_fdt_setprop_cells(fdt, node, "reg", mmio0, 0x1000); + qemu_fdt_setprop_cells(fdt, node, "interrupts", irq0, 0x2); + qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic); + qemu_fdt_setprop_cells(fdt, node, "#gpio-cells", 2); + qemu_fdt_setprop(fdt, node, "gpio-controller", NULL, 0); + + g_free(node); +} + static int ppce500_load_device_tree(MachineState *machine, PPCE500Params *params, hwaddr addr, @@ -379,6 +398,10 @@ static int ppce500_load_device_tree(MachineState *machine, qemu_fdt_setprop_cell(fdt, pci, "#address-cells", 3); qemu_fdt_setprop_string(fdt, "/aliases", "pci0", pci); + if (params->has_mpc8xxx_gpio) { + create_dt_mpc8xxx_gpio(fdt, soc, mpic); + } + params->fixup_devtree(params, fdt); if (toplevel_compat) { @@ -769,6 +792,15 @@ void ppce500_init(MachineState *machine, PPCE500Params *params) cur_base = (32 * 1024 * 1024); } + if (params->has_mpc8xxx_gpio) { + dev = qdev_create(NULL, "mpc8xxx_gpio"); + s = SYS_BUS_DEVICE(dev); + qdev_init_nofail(dev); + sysbus_connect_irq(s, 0, mpic[MPC8XXX_GPIO_IRQ]); + memory_region_add_subregion(ccsr_addr_space, MPC8XXX_GPIO_OFFSET, + sysbus_mmio_get_region(s, 0)); + } + /* Load kernel. */ if (machine->kernel_filename) { kernel_base = cur_base; diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h index 08b25fab49..83c5b8bf0f 100644 --- a/hw/ppc/e500.h +++ b/hw/ppc/e500.h @@ -11,6 +11,7 @@ typedef struct PPCE500Params { void (*fixup_devtree)(struct PPCE500Params *params, void *fdt); int mpic_version; + bool has_mpc8xxx_gpio; } PPCE500Params; void ppce500_init(MachineState *machine, PPCE500Params *params); diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c index 27df31ddb0..bafb56d9ff 100644 --- a/hw/ppc/e500plat.c +++ b/hw/ppc/e500plat.c @@ -35,6 +35,7 @@ static void e500plat_init(MachineState *machine) .pci_nr_slots = PCI_SLOT_MAX - 1, .fixup_devtree = e500plat_fixup_devtree, .mpic_version = OPENPIC_MODEL_FSL_MPIC_42, + .has_mpc8xxx_gpio = true, }; /* Older KVM versions don't support EPR which breaks guests when we announce From 016f7758985290c8ca79fc9842fd697d61cbc0b0 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 1 Oct 2014 16:05:47 +0200 Subject: [PATCH 18/34] PPC: E500: Hook up power off GPIO to GPIO controller Now that we have a working GPIO controller on the virt machine, we can use one pin to notify QEMU that the guests wants to power off the system. Signed-off-by: Alexander Graf --- hw/ppc/e500.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 304c124ffd..cfc46c4401 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -129,6 +129,8 @@ static void create_dt_mpc8xxx_gpio(void *fdt, const char *soc, const char *mpic) hwaddr mmio0 = MPC8XXX_GPIO_OFFSET; int irq0 = MPC8XXX_GPIO_IRQ; gchar *node = g_strdup_printf("%s/gpio@%"PRIx64, soc, mmio0); + gchar *poweroff = g_strdup_printf("%s/power-off", soc); + int gpio_ph; qemu_fdt_add_subnode(fdt, node); qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,qoriq-gpio"); @@ -137,8 +139,17 @@ static void create_dt_mpc8xxx_gpio(void *fdt, const char *soc, const char *mpic) qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic); qemu_fdt_setprop_cells(fdt, node, "#gpio-cells", 2); qemu_fdt_setprop(fdt, node, "gpio-controller", NULL, 0); + gpio_ph = qemu_fdt_alloc_phandle(fdt); + qemu_fdt_setprop_cell(fdt, node, "phandle", gpio_ph); + qemu_fdt_setprop_cell(fdt, node, "linux,phandle", gpio_ph); + + /* Power Off Pin */ + qemu_fdt_add_subnode(fdt, poweroff); + qemu_fdt_setprop_string(fdt, poweroff, "compatible", "gpio-poweroff"); + qemu_fdt_setprop_cells(fdt, poweroff, "gpios", gpio_ph, 0, 0); g_free(node); + g_free(poweroff); } static int ppce500_load_device_tree(MachineState *machine, @@ -641,6 +652,13 @@ static qemu_irq *ppce500_init_mpic(PPCE500Params *params, MemoryRegion *ccsr, return mpic; } +static void ppce500_power_off(void *opaque, int line, int on) +{ + if (on) { + qemu_system_shutdown_request(); + } +} + void ppce500_init(MachineState *machine, PPCE500Params *params) { MemoryRegion *address_space_mem = get_system_memory(); @@ -793,12 +811,18 @@ void ppce500_init(MachineState *machine, PPCE500Params *params) } if (params->has_mpc8xxx_gpio) { + qemu_irq poweroff_irq; + dev = qdev_create(NULL, "mpc8xxx_gpio"); s = SYS_BUS_DEVICE(dev); qdev_init_nofail(dev); sysbus_connect_irq(s, 0, mpic[MPC8XXX_GPIO_IRQ]); memory_region_add_subregion(ccsr_addr_space, MPC8XXX_GPIO_OFFSET, sysbus_mmio_get_region(s, 0)); + + /* Power Off GPIO at Pin 0 */ + poweroff_irq = qemu_allocate_irq(ppce500_power_off, NULL, 0); + qdev_connect_gpio_out(dev, 0, poweroff_irq); } /* Load kernel. */ From f58aa483145789fbcc3b8a39873ce2b45d5b8d52 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Thu, 2 Oct 2014 19:56:03 +1000 Subject: [PATCH 19/34] spapr_nvram: Enable migration The only case when sPAPR NVRAM migrates now is if is backed by a file and copy-storage migration is performed. In other cases NVRAM does not migrate regardless whether it is backed by a file or not. This enables shadow copy of NVRAM in RAM which is read from a file (if used) and used for reads. Writes to NVRAM are mirrored to the file. This defines a VMSTATE descriptor for NVRAM device so the memory copy of NVRAM can migrate and be flushed to a backing file on the destination if one is specified. Signed-off-by: Alexey Kardashevskiy Reviewed-by: David Gibson Signed-off-by: Alexander Graf --- hw/nvram/spapr_nvram.c | 81 +++++++++++++++++++++++++++++++++--------- 1 file changed, 64 insertions(+), 17 deletions(-) diff --git a/hw/nvram/spapr_nvram.c b/hw/nvram/spapr_nvram.c index 10b5b2e86b..35dc6d5684 100644 --- a/hw/nvram/spapr_nvram.c +++ b/hw/nvram/spapr_nvram.c @@ -52,7 +52,6 @@ static void rtas_nvram_fetch(PowerPCCPU *cpu, sPAPREnvironment *spapr, { sPAPRNVRAM *nvram = spapr->nvram; hwaddr offset, buffer, len; - int alen; void *membuf; if ((nargs != 3) || (nret != 2)) { @@ -77,19 +76,14 @@ static void rtas_nvram_fetch(PowerPCCPU *cpu, sPAPREnvironment *spapr, return; } - membuf = cpu_physical_memory_map(buffer, &len, 1); - if (nvram->blk) { - alen = blk_pread(nvram->blk, offset, membuf, len); - } else { - assert(nvram->buf); + assert(nvram->buf); - memcpy(membuf, nvram->buf + offset, len); - alen = len; - } + membuf = cpu_physical_memory_map(buffer, &len, 1); + memcpy(membuf, nvram->buf + offset, len); cpu_physical_memory_unmap(membuf, len, 1, len); - rtas_st(rets, 0, (alen < len) ? RTAS_OUT_HW_ERROR : RTAS_OUT_SUCCESS); - rtas_st(rets, 1, (alen < 0) ? 0 : alen); + rtas_st(rets, 0, RTAS_OUT_SUCCESS); + rtas_st(rets, 1, len); } static void rtas_nvram_store(PowerPCCPU *cpu, sPAPREnvironment *spapr, @@ -123,14 +117,15 @@ static void rtas_nvram_store(PowerPCCPU *cpu, sPAPREnvironment *spapr, } membuf = cpu_physical_memory_map(buffer, &len, 0); + + alen = len; if (nvram->blk) { alen = blk_pwrite(nvram->blk, offset, membuf, len); - } else { - assert(nvram->buf); - - memcpy(nvram->buf + offset, membuf, len); - alen = len; } + + assert(nvram->buf); + memcpy(nvram->buf + offset, membuf, len); + cpu_physical_memory_unmap(membuf, len, 0, len); rtas_st(rets, 0, (alen < len) ? RTAS_OUT_HW_ERROR : RTAS_OUT_SUCCESS); @@ -145,15 +140,24 @@ static int spapr_nvram_init(VIOsPAPRDevice *dev) nvram->size = blk_getlength(nvram->blk); } else { nvram->size = DEFAULT_NVRAM_SIZE; - nvram->buf = g_malloc0(nvram->size); } + nvram->buf = g_malloc0(nvram->size); + if ((nvram->size < MIN_NVRAM_SIZE) || (nvram->size > MAX_NVRAM_SIZE)) { fprintf(stderr, "spapr-nvram must be between %d and %d bytes in size\n", MIN_NVRAM_SIZE, MAX_NVRAM_SIZE); return -1; } + if (nvram->blk) { + int alen = blk_pread(nvram->blk, 0, nvram->buf, nvram->size); + + if (alen != nvram->size) { + return -1; + } + } + spapr_rtas_register(RTAS_NVRAM_FETCH, "nvram-fetch", rtas_nvram_fetch); spapr_rtas_register(RTAS_NVRAM_STORE, "nvram-store", rtas_nvram_store); @@ -167,6 +171,48 @@ static int spapr_nvram_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off) return fdt_setprop_cell(fdt, node_off, "#bytes", nvram->size); } +static int spapr_nvram_pre_load(void *opaque) +{ + sPAPRNVRAM *nvram = VIO_SPAPR_NVRAM(opaque); + + g_free(nvram->buf); + nvram->buf = NULL; + nvram->size = 0; + + return 0; +} + +static int spapr_nvram_post_load(void *opaque, int version_id) +{ + sPAPRNVRAM *nvram = VIO_SPAPR_NVRAM(opaque); + + if (nvram->blk) { + int alen = blk_pwrite(nvram->blk, 0, nvram->buf, nvram->size); + + if (alen < 0) { + return alen; + } + if (alen != nvram->size) { + return -1; + } + } + + return 0; +} + +static const VMStateDescription vmstate_spapr_nvram = { + .name = "spapr_nvram", + .version_id = 1, + .minimum_version_id = 1, + .pre_load = spapr_nvram_pre_load, + .post_load = spapr_nvram_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT32(size, sPAPRNVRAM), + VMSTATE_VBUFFER_ALLOC_UINT32(buf, sPAPRNVRAM, 1, NULL, 0, size), + VMSTATE_END_OF_LIST() + }, +}; + static Property spapr_nvram_properties[] = { DEFINE_SPAPR_PROPERTIES(sPAPRNVRAM, sdev), DEFINE_PROP_DRIVE("drive", sPAPRNVRAM, blk), @@ -185,6 +231,7 @@ static void spapr_nvram_class_init(ObjectClass *klass, void *data) k->dt_compatible = "qemu,spapr-nvram"; set_bit(DEVICE_CATEGORY_MISC, dc->categories); dc->props = spapr_nvram_properties; + dc->vmsd = &vmstate_spapr_nvram; } static const TypeInfo spapr_nvram_type_info = { From cc64b1a1940dc2e041c5b06b003d9acf64c22372 Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Wed, 15 Oct 2014 21:48:07 +0800 Subject: [PATCH 20/34] target-ppc: kvm: Fix memory overflow issue about strncat() strncat() will append additional '\0' to destination buffer, so need additional 1 byte for it, or may cause memory overflow, just like other area within QEMU have done. And can use g_strdup_printf() instead of strncat(), which may be more easier understanding. Signed-off-by: Chen Gang Signed-off-by: Alexander Graf --- target-ppc/kvm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 9c23c6ba0d..6843fa0b98 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -1782,7 +1782,7 @@ static int kvmppc_find_cpu_dt(char *buf, int buf_len) * format) */ static uint64_t kvmppc_read_int_cpu_dt(const char *propname) { - char buf[PATH_MAX]; + char buf[PATH_MAX], *tmp; union { uint32_t v32; uint64_t v64; @@ -1794,10 +1794,10 @@ static uint64_t kvmppc_read_int_cpu_dt(const char *propname) return -1; } - strncat(buf, "/", sizeof(buf) - strlen(buf)); - strncat(buf, propname, sizeof(buf) - strlen(buf)); + tmp = g_strdup_printf("%s/%s", buf, propname); - f = fopen(buf, "rb"); + f = fopen(tmp, "rb"); + g_free(tmp); if (!f) { return -1; } From c47493f24fd4f16cffc1130d071b783f4453b7a3 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 15 Sep 2014 17:03:28 +0200 Subject: [PATCH 21/34] ppc: do not look at the MMU index to detect PR/HV mode The MMU index is an internal detail that should not be needed by the translator (except to generate loads and stores). Look at the MSR directly. Signed-off-by: Paolo Bonzini Signed-off-by: Alexander Graf --- target-ppc/translate.c | 165 +++++++++++++++++++---------------------- 1 file changed, 77 insertions(+), 88 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 2b1fcbb5fd..f0567f7aec 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -189,6 +189,7 @@ typedef struct DisasContext { uint32_t opcode; uint32_t exception; /* Routine used to access memory */ + bool pr, hv; int mem_idx; int access_type; /* Translation flags */ @@ -643,20 +644,6 @@ static opc_handler_t invalid_handler = { .handler = gen_invalid, }; -#if defined(TARGET_PPC64) -/* NOTE: as this time, the only use of is_user_mode() is in 64 bit code. And */ -/* so the function is wrapped in the standard 64-bit ifdef in order to */ -/* avoid compiler warnings in 32-bit implementations. */ -static bool is_user_mode(DisasContext *ctx) -{ -#if defined(CONFIG_USER_ONLY) - return true; -#else - return ctx->mem_idx == 0; -#endif -} -#endif - /*** Integer comparison ***/ static inline void gen_op_cmp(TCGv arg0, TCGv arg1, int s, int crf) @@ -1456,25 +1443,25 @@ static void gen_or(DisasContext *ctx) break; #if !defined(CONFIG_USER_ONLY) case 31: - if (ctx->mem_idx > 0) { + if (!ctx->pr) { /* Set process priority to very low */ prio = 1; } break; case 5: - if (ctx->mem_idx > 0) { + if (!ctx->pr) { /* Set process priority to medium-hight */ prio = 5; } break; case 3: - if (ctx->mem_idx > 0) { + if (!ctx->pr) { /* Set process priority to high */ prio = 6; } break; case 7: - if (ctx->mem_idx > 1) { + if (ctx->hv) { /* Set process priority to very high */ prio = 7; } @@ -2901,7 +2888,7 @@ static void gen_lq(DisasContext *ctx) bool legal_in_user_mode = (ctx->insns_flags2 & PPC2_LSQ_ISA207) != 0; bool le_is_supported = (ctx->insns_flags2 & PPC2_LSQ_ISA207) != 0; - if (!legal_in_user_mode && is_user_mode(ctx)) { + if (!legal_in_user_mode && ctx->pr) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -3024,7 +3011,7 @@ static void gen_std(DisasContext *ctx) bool legal_in_user_mode = (ctx->insns_flags2 & PPC2_LSQ_ISA207) != 0; bool le_is_supported = (ctx->insns_flags2 & PPC2_LSQ_ISA207) != 0; - if (!legal_in_user_mode && is_user_mode(ctx)) { + if (!legal_in_user_mode && ctx->pr) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -4002,14 +3989,14 @@ static void gen_mcrf(DisasContext *ctx) /*** System linkage ***/ -/* rfi (mem_idx only) */ +/* rfi (supervisor only) */ static void gen_rfi(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else /* Restore CPU state */ - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -4026,7 +4013,7 @@ static void gen_rfid(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else /* Restore CPU state */ - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -4042,7 +4029,7 @@ static void gen_hrfid(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else /* Restore CPU state */ - if (unlikely(ctx->mem_idx <= 1)) { + if (unlikely(!ctx->hv)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -4211,7 +4198,7 @@ static void gen_mfmsr(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); return; } @@ -4235,9 +4222,9 @@ static inline void gen_op_mfspr(DisasContext *ctx) uint32_t sprn = SPR(ctx->opcode); #if !defined(CONFIG_USER_ONLY) - if (ctx->mem_idx == 2) + if (ctx->hv) read_cb = ctx->spr_cb[sprn].hea_read; - else if (ctx->mem_idx) + else if (!ctx->pr) read_cb = ctx->spr_cb[sprn].oea_read; else #endif @@ -4315,7 +4302,7 @@ static void gen_mtmsrd(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); return; } @@ -4346,7 +4333,7 @@ static void gen_mtmsr(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); return; } @@ -4386,9 +4373,9 @@ static void gen_mtspr(DisasContext *ctx) uint32_t sprn = SPR(ctx->opcode); #if !defined(CONFIG_USER_ONLY) - if (ctx->mem_idx == 2) + if (ctx->hv) write_cb = ctx->spr_cb[sprn].hea_write; - else if (ctx->mem_idx) + else if (!ctx->pr) write_cb = ctx->spr_cb[sprn].oea_write; else #endif @@ -4435,7 +4422,7 @@ static void gen_dcbi(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else TCGv EA, val; - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -4572,7 +4559,7 @@ static void gen_mfsr(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); #else TCGv t0; - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); return; } @@ -4589,7 +4576,7 @@ static void gen_mfsrin(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); #else TCGv t0; - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); return; } @@ -4608,7 +4595,7 @@ static void gen_mtsr(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); #else TCGv t0; - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); return; } @@ -4625,7 +4612,7 @@ static void gen_mtsrin(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); #else TCGv t0; - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); return; } @@ -4647,7 +4634,7 @@ static void gen_mfsr_64b(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); #else TCGv t0; - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); return; } @@ -4664,7 +4651,7 @@ static void gen_mfsrin_64b(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); #else TCGv t0; - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); return; } @@ -4683,7 +4670,7 @@ static void gen_mtsr_64b(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); #else TCGv t0; - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); return; } @@ -4700,7 +4687,7 @@ static void gen_mtsrin_64b(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); #else TCGv t0; - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); return; } @@ -4718,7 +4705,7 @@ static void gen_slbmte(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); return; } @@ -4732,7 +4719,7 @@ static void gen_slbmfee(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); return; } @@ -4746,7 +4733,7 @@ static void gen_slbmfev(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); return; } @@ -4757,7 +4744,7 @@ static void gen_slbmfev(DisasContext *ctx) #endif /* defined(TARGET_PPC64) */ /*** Lookaside buffer management ***/ -/* Optional & mem_idx only: */ +/* Optional & supervisor only: */ /* tlbia */ static void gen_tlbia(DisasContext *ctx) @@ -4765,7 +4752,7 @@ static void gen_tlbia(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -4779,7 +4766,7 @@ static void gen_tlbiel(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -4793,7 +4780,7 @@ static void gen_tlbie(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -4814,7 +4801,7 @@ static void gen_tlbsync(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -4832,7 +4819,7 @@ static void gen_slbia(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -4846,7 +4833,7 @@ static void gen_slbie(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -5554,7 +5541,7 @@ static void gen_mfrom(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -5570,7 +5557,7 @@ static void gen_tlbld_6xx(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -5584,7 +5571,7 @@ static void gen_tlbli_6xx(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -5600,7 +5587,7 @@ static void gen_tlbld_74xx(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -5614,7 +5601,7 @@ static void gen_tlbli_74xx(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -5637,7 +5624,7 @@ static void gen_cli(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -5658,7 +5645,7 @@ static void gen_mfsri(DisasContext *ctx) int ra = rA(ctx->opcode); int rd = rD(ctx->opcode); TCGv t0; - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -5679,7 +5666,7 @@ static void gen_rac(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else TCGv t0; - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -5695,7 +5682,7 @@ static void gen_rfsvc(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -5857,7 +5844,7 @@ static void gen_tlbiva(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else TCGv t0; - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -6090,7 +6077,7 @@ static void gen_mfdcr(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); #else TCGv dcrn; - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); return; } @@ -6109,7 +6096,7 @@ static void gen_mtdcr(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); #else TCGv dcrn; - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); return; } @@ -6128,7 +6115,7 @@ static void gen_mfdcrx(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); return; } @@ -6147,7 +6134,7 @@ static void gen_mtdcrx(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); return; } @@ -6185,7 +6172,7 @@ static void gen_dccci(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -6200,7 +6187,7 @@ static void gen_dcread(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else TCGv EA, val; - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -6230,7 +6217,7 @@ static void gen_iccci(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -6244,7 +6231,7 @@ static void gen_icread(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -6252,13 +6239,13 @@ static void gen_icread(DisasContext *ctx) #endif } -/* rfci (mem_idx only) */ +/* rfci (supervisor only) */ static void gen_rfci_40x(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -6273,7 +6260,7 @@ static void gen_rfci(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -6291,7 +6278,7 @@ static void gen_rfdi(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -6307,7 +6294,7 @@ static void gen_rfmci(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -6325,7 +6312,7 @@ static void gen_tlbre_40x(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -6352,7 +6339,7 @@ static void gen_tlbsx_40x(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else TCGv t0; - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -6376,7 +6363,7 @@ static void gen_tlbwe_40x(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -6404,7 +6391,7 @@ static void gen_tlbre_440(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -6433,7 +6420,7 @@ static void gen_tlbsx_440(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else TCGv t0; - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -6457,7 +6444,7 @@ static void gen_tlbwe_440(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -6487,7 +6474,7 @@ static void gen_tlbre_booke206(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -6503,7 +6490,7 @@ static void gen_tlbsx_booke206(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else TCGv t0; - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -6527,7 +6514,7 @@ static void gen_tlbwe_booke206(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -6542,7 +6529,7 @@ static void gen_tlbivax_booke206(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else TCGv t0; - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -6561,7 +6548,7 @@ static void gen_tlbilx_booke206(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else TCGv t0; - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -6596,7 +6583,7 @@ static void gen_wrtee(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else TCGv t0; - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -6618,7 +6605,7 @@ static void gen_wrteei(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else - if (unlikely(!ctx->mem_idx)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -6671,7 +6658,7 @@ static void gen_msgclr(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else - if (unlikely(ctx->mem_idx == 0)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -6685,7 +6672,7 @@ static void gen_msgsnd(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else - if (unlikely(ctx->mem_idx == 0)) { + if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -11298,6 +11285,8 @@ static inline void gen_intermediate_code_internal(PowerPCCPU *cpu, ctx.tb = tb; ctx.exception = POWERPC_EXCP_NONE; ctx.spr_cb = env->spr_cb; + ctx.pr = msr_pr; + ctx.hv = !msr_pr && msr_hv; ctx.mem_idx = env->mmu_idx; ctx.insns_flags = env->insns_flags; ctx.insns_flags2 = env->insns_flags2; From f8833a37c0c6b22ddd57b45e48cfb0f97dbd5af4 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 22 Oct 2014 18:41:07 +0100 Subject: [PATCH 22/34] hw/ppc/spapr_pci.c: Avoid functions not in glib 2.12 (g_hash_table_iter_*) The g_hash_table_iter_* functions for iterating through a hash table are not present in glib 2.12, which is our current minimum requirement. Rewrite the code to use g_hash_table_foreach() instead. Signed-off-by: Peter Maydell Signed-off-by: Alexander Graf --- hw/ppc/spapr_pci.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index ad0da7fdc4..21b95b342c 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -704,28 +704,34 @@ static const VMStateDescription vmstate_spapr_pci_msi = { }, }; +static void spapr_pci_fill_msi_devs(gpointer key, gpointer value, + gpointer opaque) +{ + sPAPRPHBState *sphb = opaque; + + sphb->msi_devs[sphb->msi_devs_num].key = *(uint32_t *)key; + sphb->msi_devs[sphb->msi_devs_num].value = *(spapr_pci_msi *)value; + sphb->msi_devs_num++; +} + static void spapr_pci_pre_save(void *opaque) { sPAPRPHBState *sphb = opaque; - GHashTableIter iter; - gpointer key, value; - int i; + int msi_devs_num; if (sphb->msi_devs) { g_free(sphb->msi_devs); sphb->msi_devs = NULL; } - sphb->msi_devs_num = g_hash_table_size(sphb->msi); - if (!sphb->msi_devs_num) { + sphb->msi_devs_num = 0; + msi_devs_num = g_hash_table_size(sphb->msi); + if (!msi_devs_num) { return; } - sphb->msi_devs = g_malloc(sphb->msi_devs_num * sizeof(spapr_pci_msi_mig)); + sphb->msi_devs = g_malloc(msi_devs_num * sizeof(spapr_pci_msi_mig)); - g_hash_table_iter_init(&iter, sphb->msi); - for (i = 0; g_hash_table_iter_next(&iter, &key, &value); ++i) { - sphb->msi_devs[i].key = *(uint32_t *) key; - sphb->msi_devs[i].value = *(spapr_pci_msi *) value; - } + g_hash_table_foreach(sphb->msi, spapr_pci_fill_msi_devs, sphb); + assert(sphb->msi_devs_num == msi_devs_num); } static int spapr_pci_post_load(void *opaque, int version_id) From eb5722801c84f23428c50e2336d02e400ce55deb Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 24 Sep 2014 13:06:57 +0200 Subject: [PATCH 23/34] sysbus: Add dynamic sysbus device search Sysbus devices can be spawned by C code or dynamically via the command line. In the latter case, we need to be able to find the dynamically created devices to do things with them. This patch adds a search helper that makes it easy to look for dynamically spawned sysbus devices. Signed-off-by: Alexander Graf --- hw/core/sysbus.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ include/hw/sysbus.h | 5 +++++ 2 files changed, 50 insertions(+) diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c index e55c3c1d6d..19437e65f7 100644 --- a/hw/core/sysbus.c +++ b/hw/core/sysbus.c @@ -24,6 +24,51 @@ static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent); static char *sysbus_get_fw_dev_path(DeviceState *dev); +typedef struct SysBusFind { + void *opaque; + FindSysbusDeviceFunc *func; +} SysBusFind; + +/* Run func() for every sysbus device, traverse the tree for everything else */ +static int find_sysbus_device(Object *obj, void *opaque) +{ + SysBusFind *find = opaque; + Object *dev; + SysBusDevice *sbdev; + + dev = object_dynamic_cast(obj, TYPE_SYS_BUS_DEVICE); + sbdev = (SysBusDevice *)dev; + + if (!sbdev) { + /* Container, traverse it for children */ + return object_child_foreach(obj, find_sysbus_device, opaque); + } + + find->func(sbdev, find->opaque); + + return 0; +} + +/* + * Loop through all dynamically created sysbus devices and call + * func() for each instance. + */ +void foreach_dynamic_sysbus_device(FindSysbusDeviceFunc *func, void *opaque) +{ + Object *container; + SysBusFind find = { + .func = func, + .opaque = opaque, + }; + + /* Loop through all sysbus devices that were spawened outside the machine */ + container = container_get(qdev_get_machine(), "/peripheral"); + find_sysbus_device(container, &find); + container = container_get(qdev_get_machine(), "/peripheral-anon"); + find_sysbus_device(container, &find); +} + + static void system_bus_class_init(ObjectClass *klass, void *data) { BusClass *k = BUS_CLASS(klass); diff --git a/include/hw/sysbus.h b/include/hw/sysbus.h index 9fb1782d7b..80529ffed8 100644 --- a/include/hw/sysbus.h +++ b/include/hw/sysbus.h @@ -57,6 +57,8 @@ struct SysBusDevice { pio_addr_t pio[QDEV_MAX_PIO]; }; +typedef int FindSysbusDeviceFunc(SysBusDevice *sbdev, void *opaque); + void sysbus_init_mmio(SysBusDevice *dev, MemoryRegion *memory); MemoryRegion *sysbus_mmio_get_region(SysBusDevice *dev, int n); void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p); @@ -72,6 +74,9 @@ void sysbus_add_io(SysBusDevice *dev, hwaddr addr, MemoryRegion *mem); MemoryRegion *sysbus_address_space(SysBusDevice *dev); +/* Call func for every dynamically created sysbus device in the system */ +void foreach_dynamic_sysbus_device(FindSysbusDeviceFunc *func, void *opaque); + /* Legacy helper function for creating devices. */ DeviceState *sysbus_create_varargs(const char *name, hwaddr addr, ...); From 33cd52b5d7b9adfd009e95f07e6c64dd88ae2a31 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 1 Jul 2014 16:14:41 +0200 Subject: [PATCH 24/34] sysbus: Make devices spawnable via -device Now that we can properly map sysbus devices that haven't been connected to something forcefully by C code, we can allow the -device command line option to spawn them. For machines that don't implement dynamic sysbus assignment in their board files we add a new bool "has_dynamic_sysbus" to the machine class. When that property is false (default), we bail out when we see dynamically spawned sysbus devices, like we did before. Signed-off-by: Alexander Graf --- hw/core/machine.c | 34 ++++++++++++++++++++++++++++++++++ hw/core/sysbus.c | 7 ------- include/hw/boards.h | 8 ++++++-- vl.c | 1 + 4 files changed, 41 insertions(+), 9 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index 7f3418c5af..19d3e3a707 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -12,6 +12,9 @@ #include "hw/boards.h" #include "qapi/visitor.h" +#include "hw/sysbus.h" +#include "sysemu/sysemu.h" +#include "qemu/error-report.h" static char *machine_get_accel(Object *obj, Error **errp) { @@ -257,8 +260,35 @@ static void machine_set_iommu(Object *obj, bool value, Error **errp) ms->iommu = value; } +static int error_on_sysbus_device(SysBusDevice *sbdev, void *opaque) +{ + error_report("Option '-device %s' cannot be handled by this machine", + object_class_get_name(object_get_class(OBJECT(sbdev)))); + exit(1); +} + +static void machine_init_notify(Notifier *notifier, void *data) +{ + Object *machine = qdev_get_machine(); + ObjectClass *oc = object_get_class(machine); + MachineClass *mc = MACHINE_CLASS(oc); + + if (mc->has_dynamic_sysbus) { + /* Our machine can handle dynamic sysbus devices, we're all good */ + return; + } + + /* + * Loop through all dynamically created devices and check whether there + * are sysbus devices among them. If there are, error out. + */ + foreach_dynamic_sysbus_device(error_on_sysbus_device, NULL); +} + static void machine_initfn(Object *obj) { + MachineState *ms = MACHINE(obj); + object_property_add_str(obj, "accel", machine_get_accel, machine_set_accel, NULL); object_property_add_bool(obj, "kernel-irqchip", @@ -303,6 +333,10 @@ static void machine_initfn(Object *obj) object_property_add_bool(obj, "iommu", machine_get_iommu, machine_set_iommu, NULL); + + /* Register notifier when init is done for sysbus sanity checks */ + ms->sysbus_notifier.notify = machine_init_notify; + qemu_add_machine_init_done_notifier(&ms->sysbus_notifier); } static void machine_finalize(Object *obj) diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c index 19437e65f7..7bfe381cd8 100644 --- a/hw/core/sysbus.c +++ b/hw/core/sysbus.c @@ -283,13 +283,6 @@ static void sysbus_device_class_init(ObjectClass *klass, void *data) DeviceClass *k = DEVICE_CLASS(klass); k->init = sysbus_device_init; k->bus_type = TYPE_SYSTEM_BUS; - /* - * device_add plugs devices into suitable bus. For "real" buses, - * that actually connects the device. For sysbus, the connections - * need to be made separately, and device_add can't do that. The - * device would be left unconnected, and could not possibly work. - */ - k->cannot_instantiate_with_device_add_yet = true; } static const TypeInfo sysbus_device_type_info = { diff --git a/include/hw/boards.h b/include/hw/boards.h index 99a172d652..e0a67903ef 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -36,7 +36,8 @@ struct QEMUMachine { use_sclp:1, no_floppy:1, no_cdrom:1, - no_sdcard:1; + no_sdcard:1, + has_dynamic_sysbus:1; int is_default; const char *default_machine_opts; const char *default_boot_order; @@ -97,7 +98,8 @@ struct MachineClass { use_sclp:1, no_floppy:1, no_cdrom:1, - no_sdcard:1; + no_sdcard:1, + has_dynamic_sysbus:1; int is_default; const char *default_machine_opts; const char *default_boot_order; @@ -115,6 +117,8 @@ struct MachineClass { struct MachineState { /*< private >*/ Object parent_obj; + Notifier sysbus_notifier; + /*< public >*/ char *accel; diff --git a/vl.c b/vl.c index 8999f364dd..f4a6e5e05b 100644 --- a/vl.c +++ b/vl.c @@ -1441,6 +1441,7 @@ static void machine_class_init(ObjectClass *oc, void *data) mc->no_floppy = qm->no_floppy; mc->no_cdrom = qm->no_cdrom; mc->no_sdcard = qm->no_sdcard; + mc->has_dynamic_sysbus = qm->has_dynamic_sysbus; mc->is_default = qm->is_default; mc->default_machine_opts = qm->default_machine_opts; mc->default_boot_order = qm->default_boot_order; From b797318666dade9675a253d311125ae7b568e2f8 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 24 Sep 2014 12:32:17 +0200 Subject: [PATCH 25/34] sysbus: Expose IRQ enumeration helpers Sysbus devices can get their IRQ lines connected to other devices. It is possible to figure out which IRQ line a connection is on and whether a sysbus device even provides an IRQ connector at a specific offset. This patch exposes helpers to make this information publicly accessible. We will need it for the platform bus dynamic sysbus enumeration. Signed-off-by: Alexander Graf --- hw/core/qdev.c | 11 +++++++++++ hw/core/sysbus.c | 21 +++++++++++++++++++++ include/hw/qdev-core.h | 1 + include/hw/sysbus.h | 3 +++ 4 files changed, 36 insertions(+) diff --git a/hw/core/qdev.c b/hw/core/qdev.c index b3d519645a..413b41376f 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -453,6 +453,17 @@ void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n, g_free(propname); } +qemu_irq qdev_get_gpio_out_connector(DeviceState *dev, const char *name, int n) +{ + char *propname = g_strdup_printf("%s[%d]", + name ? name : "unnamed-gpio-out", n); + + qemu_irq ret = (qemu_irq)object_property_get_link(OBJECT(dev), propname, + NULL); + + return ret; +} + /* disconnect a GPIO ouput, returning the disconnected input (if any) */ static qemu_irq qdev_disconnect_gpio_out_named(DeviceState *dev, diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c index 7bfe381cd8..945dec53d0 100644 --- a/hw/core/sysbus.c +++ b/hw/core/sysbus.c @@ -84,6 +84,27 @@ static const TypeInfo system_bus_info = { .class_init = system_bus_class_init, }; +/* Check whether an IRQ source exists */ +bool sysbus_has_irq(SysBusDevice *dev, int n) +{ + char *prop = g_strdup_printf("%s[%d]", SYSBUS_DEVICE_GPIO_IRQ, n); + ObjectProperty *r; + + r = object_property_find(OBJECT(dev), prop, NULL); + return (r != NULL); +} + +bool sysbus_is_irq_connected(SysBusDevice *dev, int n) +{ + return !!sysbus_get_connected_irq(dev, n); +} + +qemu_irq sysbus_get_connected_irq(SysBusDevice *dev, int n) +{ + DeviceState *d = DEVICE(dev); + return qdev_get_gpio_out_connector(d, SYSBUS_DEVICE_GPIO_IRQ, n); +} + void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq) { qdev_connect_gpio_out_named(DEVICE(dev), SYSBUS_DEVICE_GPIO_IRQ, n, irq); diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index 00a15a3977..d3a29408d4 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -272,6 +272,7 @@ qemu_irq qdev_get_gpio_in_named(DeviceState *dev, const char *name, int n); void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin); void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n, qemu_irq pin); +qemu_irq qdev_get_gpio_out_connector(DeviceState *dev, const char *name, int n); qemu_irq qdev_intercept_gpio_out(DeviceState *dev, qemu_irq icpt, const char *name, int n); diff --git a/include/hw/sysbus.h b/include/hw/sysbus.h index 80529ffed8..2a3cfa785f 100644 --- a/include/hw/sysbus.h +++ b/include/hw/sysbus.h @@ -66,7 +66,10 @@ void sysbus_pass_irq(SysBusDevice *dev, SysBusDevice *target); void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size); +bool sysbus_has_irq(SysBusDevice *dev, int n); void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq); +bool sysbus_is_irq_connected(SysBusDevice *dev, int n); +qemu_irq sysbus_get_connected_irq(SysBusDevice *dev, int n); void sysbus_mmio_map(SysBusDevice *dev, int n, hwaddr addr); void sysbus_mmio_map_overlap(SysBusDevice *dev, int n, hwaddr addr, int priority); From 471a9bc14444e79bb826616becd2e5531e591d30 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 24 Sep 2014 12:36:30 +0200 Subject: [PATCH 26/34] sysbus: Expose MMIO enumeration helper Sysbus devices have a range of MMIO regions they expose. The exact number of regions is device specific and internal information to the device model. Expose whether a region exists via a public interface. That way our platform bus enumeration code can dynamically determine how many regions exist. Signed-off-by: Alexander Graf --- hw/core/sysbus.c | 6 ++++++ include/hw/sysbus.h | 1 + 2 files changed, 7 insertions(+) diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c index 945dec53d0..84af59379d 100644 --- a/hw/core/sysbus.c +++ b/hw/core/sysbus.c @@ -110,6 +110,12 @@ void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq) qdev_connect_gpio_out_named(DEVICE(dev), SYSBUS_DEVICE_GPIO_IRQ, n, irq); } +/* Check whether an MMIO region exists */ +bool sysbus_has_mmio(SysBusDevice *dev, unsigned int n) +{ + return (n < dev->num_mmio); +} + static void sysbus_mmio_map_common(SysBusDevice *dev, int n, hwaddr addr, bool may_overlap, int priority) { diff --git a/include/hw/sysbus.h b/include/hw/sysbus.h index 2a3cfa785f..6175bf990a 100644 --- a/include/hw/sysbus.h +++ b/include/hw/sysbus.h @@ -67,6 +67,7 @@ void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size); bool sysbus_has_irq(SysBusDevice *dev, int n); +bool sysbus_has_mmio(SysBusDevice *dev, unsigned int n); void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq); bool sysbus_is_irq_connected(SysBusDevice *dev, int n); qemu_irq sysbus_get_connected_irq(SysBusDevice *dev, int n); From 7634fe3c273ca2f2eb992b3b6bb7796b85558377 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 24 Sep 2014 13:16:11 +0200 Subject: [PATCH 27/34] sysbus: Add new platform bus helper device We need to support spawning of sysbus devices dynamically via the command line. The easiest way to represent these dynamically spawned devices in the guest's memory and IRQ layout is by preallocating some space for dynamic sysbus devices. This is what the "platform bus" device does. It is a sysbus device that exports a configurably sized MMIO region and a configurable number of IRQ lines. When this device encounters sysbus devices that have been dynamically created and not manually wired up, it dynamically connects them to its own pool of resources. The machine model can then loop through all of these devices and create a guest configuration (device tree) to make them visible to the guest. Signed-off-by: Alexander Graf --- hw/core/Makefile.objs | 1 + hw/core/platform-bus.c | 253 ++++++++++++++++++++++++++++++++++++++ include/hw/platform-bus.h | 57 +++++++++ 3 files changed, 311 insertions(+) create mode 100644 hw/core/platform-bus.c create mode 100644 include/hw/platform-bus.h diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs index 17845df3f0..9dce1bc53c 100644 --- a/hw/core/Makefile.objs +++ b/hw/core/Makefile.objs @@ -14,3 +14,4 @@ common-obj-$(CONFIG_SOFTMMU) += machine.o common-obj-$(CONFIG_SOFTMMU) += null-machine.o common-obj-$(CONFIG_SOFTMMU) += loader.o common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o +common-obj-$(CONFIG_SOFTMMU) += platform-bus.o diff --git a/hw/core/platform-bus.c b/hw/core/platform-bus.c new file mode 100644 index 0000000000..0f052b3338 --- /dev/null +++ b/hw/core/platform-bus.c @@ -0,0 +1,253 @@ +/* + * Platform Bus device to support dynamic Sysbus devices + * + * Copyright (C) 2014 Freescale Semiconductor, Inc. All rights reserved. + * + * Author: Alexander Graf, + * + * 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 . + */ + +#include "hw/platform-bus.h" +#include "monitor/monitor.h" +#include "exec/address-spaces.h" +#include "sysemu/sysemu.h" + + +/* + * Returns the PlatformBus IRQ number for a SysBusDevice irq number or -1 if + * the IRQ is not mapped on this Platform bus. + */ +int platform_bus_get_irqn(PlatformBusDevice *pbus, SysBusDevice *sbdev, + int n) +{ + qemu_irq sbirq = sysbus_get_connected_irq(sbdev, n); + int i; + + for (i = 0; i < pbus->num_irqs; i++) { + if (pbus->irqs[i] == sbirq) { + return i; + } + } + + /* IRQ not mapped on platform bus */ + return -1; +} + +/* + * Returns the PlatformBus MMIO region offset for Region n of a SysBusDevice or + * -1 if the region is not mapped on this Platform bus. + */ +hwaddr platform_bus_get_mmio_addr(PlatformBusDevice *pbus, SysBusDevice *sbdev, + int n) +{ + MemoryRegion *pbus_mr = &pbus->mmio; + MemoryRegion *sbdev_mr = sysbus_mmio_get_region(sbdev, n); + Object *pbus_mr_obj = OBJECT(pbus_mr); + Object *parent_mr; + + if (!memory_region_is_mapped(sbdev_mr)) { + /* Region is not mapped? */ + return -1; + } + + parent_mr = object_property_get_link(OBJECT(sbdev_mr), "container", NULL); + + assert(parent_mr); + if (parent_mr != pbus_mr_obj) { + /* MMIO region is not mapped on platform bus */ + return -1; + } + + return object_property_get_int(OBJECT(sbdev_mr), "addr", NULL); +} + +static int platform_bus_count_irqs(SysBusDevice *sbdev, void *opaque) +{ + PlatformBusDevice *pbus = opaque; + qemu_irq sbirq; + int n, i; + + for (n = 0; ; n++) { + if (!sysbus_has_irq(sbdev, n)) { + break; + } + + sbirq = sysbus_get_connected_irq(sbdev, n); + for (i = 0; i < pbus->num_irqs; i++) { + if (pbus->irqs[i] == sbirq) { + bitmap_set(pbus->used_irqs, i, 1); + break; + } + } + } + + return 0; +} + +/* + * Loop through all sysbus devices and look for unassigned IRQ lines as well as + * unassociated MMIO regions. Connect them to the platform bus if available. + */ +static void plaform_bus_refresh_irqs(PlatformBusDevice *pbus) +{ + bitmap_zero(pbus->used_irqs, pbus->num_irqs); + foreach_dynamic_sysbus_device(platform_bus_count_irqs, pbus); + pbus->done_gathering = true; +} + +static int platform_bus_map_irq(PlatformBusDevice *pbus, SysBusDevice *sbdev, + int n) +{ + int max_irqs = pbus->num_irqs; + int irqn; + + if (sysbus_is_irq_connected(sbdev, n)) { + /* IRQ is already mapped, nothing to do */ + return 0; + } + + irqn = find_first_zero_bit(pbus->used_irqs, max_irqs); + if (irqn >= max_irqs) { + hw_error("Platform Bus: Can not fit IRQ line"); + return -1; + } + + set_bit(irqn, pbus->used_irqs); + sysbus_connect_irq(sbdev, n, pbus->irqs[irqn]); + + return 0; +} + +static int platform_bus_map_mmio(PlatformBusDevice *pbus, SysBusDevice *sbdev, + int n) +{ + MemoryRegion *sbdev_mr = sysbus_mmio_get_region(sbdev, n); + uint64_t size = memory_region_size(sbdev_mr); + uint64_t alignment = (1ULL << (63 - clz64(size + size - 1))); + uint64_t off; + bool found_region = false; + + if (memory_region_is_mapped(sbdev_mr)) { + /* Region is already mapped, nothing to do */ + return 0; + } + + /* + * Look for empty space in the MMIO space that is naturally aligned with + * the target device's memory region + */ + for (off = 0; off < pbus->mmio_size; off += alignment) { + if (!memory_region_find(&pbus->mmio, off, size).mr) { + found_region = true; + break; + } + } + + if (!found_region) { + hw_error("Platform Bus: Can not fit MMIO region of size %"PRIx64, size); + } + + /* Map the device's region into our Platform Bus MMIO space */ + memory_region_add_subregion(&pbus->mmio, off, sbdev_mr); + + return 0; +} + +/* + * For each sysbus device, look for unassigned IRQ lines as well as + * unassociated MMIO regions. Connect them to the platform bus if available. + */ +static int link_sysbus_device(SysBusDevice *sbdev, void *opaque) +{ + PlatformBusDevice *pbus = opaque; + int i; + + for (i = 0; sysbus_has_irq(sbdev, i); i++) { + platform_bus_map_irq(pbus, sbdev, i); + } + + for (i = 0; sysbus_has_mmio(sbdev, i); i++) { + platform_bus_map_mmio(pbus, sbdev, i); + } + + return 0; +} + +static void platform_bus_init_notify(Notifier *notifier, void *data) +{ + PlatformBusDevice *pb = container_of(notifier, PlatformBusDevice, notifier); + + /* + * Generate a bitmap of used IRQ lines, as the user might have specified + * them on the command line. + */ + plaform_bus_refresh_irqs(pb); + + foreach_dynamic_sysbus_device(link_sysbus_device, pb); +} + +static void platform_bus_realize(DeviceState *dev, Error **errp) +{ + PlatformBusDevice *pbus; + SysBusDevice *d; + int i; + + d = SYS_BUS_DEVICE(dev); + pbus = PLATFORM_BUS_DEVICE(dev); + + memory_region_init(&pbus->mmio, NULL, "platform bus", pbus->mmio_size); + sysbus_init_mmio(d, &pbus->mmio); + + pbus->used_irqs = bitmap_new(pbus->num_irqs); + pbus->irqs = g_new0(qemu_irq, pbus->num_irqs); + for (i = 0; i < pbus->num_irqs; i++) { + sysbus_init_irq(d, &pbus->irqs[i]); + } + + /* + * Register notifier that allows us to gather dangling devices once the + * machine is completely assembled + */ + pbus->notifier.notify = platform_bus_init_notify; + qemu_add_machine_init_done_notifier(&pbus->notifier); +} + +static Property platform_bus_properties[] = { + DEFINE_PROP_UINT32("num_irqs", PlatformBusDevice, num_irqs, 0), + DEFINE_PROP_UINT32("mmio_size", PlatformBusDevice, mmio_size, 0), + DEFINE_PROP_END_OF_LIST() +}; + +static void platform_bus_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = platform_bus_realize; + dc->props = platform_bus_properties; +} + +static const TypeInfo platform_bus_info = { + .name = TYPE_PLATFORM_BUS_DEVICE, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PlatformBusDevice), + .class_init = platform_bus_class_init, +}; + +static void platform_bus_register_types(void) +{ + type_register_static(&platform_bus_info); +} + +type_init(platform_bus_register_types) diff --git a/include/hw/platform-bus.h b/include/hw/platform-bus.h new file mode 100644 index 0000000000..bd42b83809 --- /dev/null +++ b/include/hw/platform-bus.h @@ -0,0 +1,57 @@ +#ifndef HW_PLATFORM_BUS_H +#define HW_PLATFORM_BUS_H 1 + +/* + * Platform Bus device to support dynamic Sysbus devices + * + * Copyright (C) 2014 Freescale Semiconductor, Inc. All rights reserved. + * + * Author: Alexander Graf, + * + * 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 . + */ + +#include "hw/sysbus.h" + +typedef struct PlatformBusDevice PlatformBusDevice; + +#define TYPE_PLATFORM_BUS_DEVICE "platform-bus-device" +#define PLATFORM_BUS_DEVICE(obj) \ + OBJECT_CHECK(PlatformBusDevice, (obj), TYPE_PLATFORM_BUS_DEVICE) +#define PLATFORM_BUS_DEVICE_CLASS(klass) \ + OBJECT_CLASS_CHECK(PlatformBusDeviceClass, (klass), TYPE_PLATFORM_BUS_DEVICE) +#define PLATFORM_BUS_DEVICE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(PlatformBusDeviceClass, (obj), TYPE_PLATFORM_BUS_DEVICE) + +struct PlatformBusDevice { + /*< private >*/ + SysBusDevice parent_obj; + Notifier notifier; + bool done_gathering; + + /*< public >*/ + uint32_t mmio_size; + MemoryRegion mmio; + + uint32_t num_irqs; + qemu_irq *irqs; + unsigned long *used_irqs; +}; + +int platform_bus_get_irqn(PlatformBusDevice *platform_bus, SysBusDevice *sbdev, + int n); +hwaddr platform_bus_get_mmio_addr(PlatformBusDevice *pbus, SysBusDevice *sbdev, + int n); + +#endif /* !HW_PLATFORM_BUS_H */ From f70873438d40ccda3d1614ec18a141aad5da2778 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 1 Jul 2014 16:27:09 +0200 Subject: [PATCH 28/34] PPC: e500: Support dynamically spawned sysbus devices For e500 our approach to supporting dynamically spawned sysbus devices is to create a simple bus from the guest's point of view within which we map those devices dynamically. We allocate memory regions always within the "platform" hole in address space and map IRQs to predetermined IRQ lines that are reserved for platform device usage. This maps really nicely into device tree logic, so we can just tell the guest about our virtual simple bus in device tree as well. Signed-off-by: Alexander Graf --- hw/ppc/e500.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++ hw/ppc/e500.h | 5 +++ hw/ppc/e500plat.c | 6 +++ 3 files changed, 111 insertions(+) diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index cfc46c4401..123379dd65 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -36,6 +36,8 @@ #include "exec/address-spaces.h" #include "qemu/host-utils.h" #include "hw/pci-host/ppce500.h" +#include "qemu/error-report.h" +#include "hw/platform-bus.h" #define EPAPR_MAGIC (0x45504150) #define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb" @@ -152,6 +154,72 @@ static void create_dt_mpc8xxx_gpio(void *fdt, const char *soc, const char *mpic) g_free(poweroff); } +typedef struct PlatformDevtreeData { + void *fdt; + const char *mpic; + int irq_start; + const char *node; + PlatformBusDevice *pbus; +} PlatformDevtreeData; + +static int sysbus_device_create_devtree(SysBusDevice *sbdev, void *opaque) +{ + PlatformDevtreeData *data = opaque; + bool matched = false; + + if (!matched) { + error_report("Device %s is not supported by this machine yet.", + qdev_fw_name(DEVICE(sbdev))); + exit(1); + } + + return 0; +} + +static void platform_bus_create_devtree(PPCE500Params *params, void *fdt, + const char *mpic) +{ + gchar *node = g_strdup_printf("/platform@%"PRIx64, params->platform_bus_base); + const char platcomp[] = "qemu,platform\0simple-bus"; + uint64_t addr = params->platform_bus_base; + uint64_t size = params->platform_bus_size; + int irq_start = params->platform_bus_first_irq; + PlatformBusDevice *pbus; + DeviceState *dev; + + /* Create a /platform node that we can put all devices into */ + + qemu_fdt_add_subnode(fdt, node); + qemu_fdt_setprop(fdt, node, "compatible", platcomp, sizeof(platcomp)); + + /* Our platform bus region is less than 32bit big, so 1 cell is enough for + address and size */ + qemu_fdt_setprop_cells(fdt, node, "#size-cells", 1); + qemu_fdt_setprop_cells(fdt, node, "#address-cells", 1); + qemu_fdt_setprop_cells(fdt, node, "ranges", 0, addr >> 32, addr, size); + + qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic); + + dev = qdev_find_recursive(sysbus_get_default(), TYPE_PLATFORM_BUS_DEVICE); + pbus = PLATFORM_BUS_DEVICE(dev); + + /* We can only create dt nodes for dynamic devices when they're ready */ + if (pbus->done_gathering) { + PlatformDevtreeData data = { + .fdt = fdt, + .mpic = mpic, + .irq_start = irq_start, + .node = node, + .pbus = pbus, + }; + + /* Loop through all dynamic sysbus devices and create nodes for them */ + foreach_dynamic_sysbus_device(sysbus_device_create_devtree, &data); + } + + g_free(node); +} + static int ppce500_load_device_tree(MachineState *machine, PPCE500Params *params, hwaddr addr, @@ -413,6 +481,10 @@ static int ppce500_load_device_tree(MachineState *machine, create_dt_mpc8xxx_gpio(fdt, soc, mpic); } + if (params->has_platform_bus) { + platform_bus_create_devtree(params, fdt, mpic); + } + params->fixup_devtree(params, fdt); if (toplevel_compat) { @@ -441,6 +513,7 @@ typedef struct DeviceTreeParams { hwaddr initrd_size; hwaddr kernel_base; hwaddr kernel_size; + Notifier notifier; } DeviceTreeParams; static void ppce500_reset_device_tree(void *opaque) @@ -451,6 +524,12 @@ static void ppce500_reset_device_tree(void *opaque) false); } +static void ppce500_init_notify(Notifier *notifier, void *data) +{ + DeviceTreeParams *p = container_of(notifier, DeviceTreeParams, notifier); + ppce500_reset_device_tree(p); +} + static int ppce500_prep_device_tree(MachineState *machine, PPCE500Params *params, hwaddr addr, @@ -469,6 +548,8 @@ static int ppce500_prep_device_tree(MachineState *machine, p->kernel_size = kernel_size; qemu_register_reset(ppce500_reset_device_tree, p); + p->notifier.notify = ppce500_init_notify; + qemu_add_machine_init_done_notifier(&p->notifier); /* Issue the device tree loader once, so that we get the size of the blob */ return ppce500_load_device_tree(machine, params, addr, initrd_base, @@ -825,6 +906,25 @@ void ppce500_init(MachineState *machine, PPCE500Params *params) qdev_connect_gpio_out(dev, 0, poweroff_irq); } + /* Platform Bus Device */ + if (params->has_platform_bus) { + dev = qdev_create(NULL, TYPE_PLATFORM_BUS_DEVICE); + dev->id = TYPE_PLATFORM_BUS_DEVICE; + qdev_prop_set_uint32(dev, "num_irqs", params->platform_bus_num_irqs); + qdev_prop_set_uint32(dev, "mmio_size", params->platform_bus_size); + qdev_init_nofail(dev); + s = SYS_BUS_DEVICE(dev); + + for (i = 0; i < params->platform_bus_num_irqs; i++) { + int irqn = params->platform_bus_first_irq + i; + sysbus_connect_irq(s, i, mpic[irqn]); + } + + memory_region_add_subregion(address_space_mem, + params->platform_bus_base, + sysbus_mmio_get_region(s, 0)); + } + /* Load kernel. */ if (machine->kernel_filename) { kernel_base = cur_base; diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h index 83c5b8bf0f..9f61ab2b1c 100644 --- a/hw/ppc/e500.h +++ b/hw/ppc/e500.h @@ -12,6 +12,11 @@ typedef struct PPCE500Params { int mpic_version; bool has_mpc8xxx_gpio; + bool has_platform_bus; + hwaddr platform_bus_base; + hwaddr platform_bus_size; + int platform_bus_first_irq; + int platform_bus_num_irqs; } PPCE500Params; void ppce500_init(MachineState *machine, PPCE500Params *params); diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c index bafb56d9ff..d50ae000ee 100644 --- a/hw/ppc/e500plat.c +++ b/hw/ppc/e500plat.c @@ -36,6 +36,11 @@ static void e500plat_init(MachineState *machine) .fixup_devtree = e500plat_fixup_devtree, .mpic_version = OPENPIC_MODEL_FSL_MPIC_42, .has_mpc8xxx_gpio = true, + .has_platform_bus = true, + .platform_bus_base = 0xf00000000ULL, + .platform_bus_size = (128ULL * 1024 * 1024), + .platform_bus_first_irq = 5, + .platform_bus_num_irqs = 10, }; /* Older KVM versions don't support EPR which breaks guests when we announce @@ -52,6 +57,7 @@ static QEMUMachine e500plat_machine = { .desc = "generic paravirt e500 platform", .init = e500plat_init, .max_cpus = 32, + .has_dynamic_sysbus = true, }; static void e500plat_machine_init(void) From fdfb7f2cdb2d0ed364a8c8c538d0ece8c464b534 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 1 Jul 2014 23:30:06 +0200 Subject: [PATCH 29/34] e500: Add support for eTSEC in device tree This patch adds support to expose eTSEC devices in the dynamically created guest facing device tree. This allows us to expose eTSEC devices into guests without changes in the machine file. Because we can now tell the guest about eTSEC devices this patch allows the user to specify eTSEC devices via -device at all. Signed-off-by: Alexander Graf --- hw/ppc/e500.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 123379dd65..2832fc0da4 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -38,6 +38,7 @@ #include "hw/pci-host/ppce500.h" #include "qemu/error-report.h" #include "hw/platform-bus.h" +#include "hw/net/fsl_etsec/etsec.h" #define EPAPR_MAGIC (0x45504150) #define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb" @@ -162,11 +163,53 @@ typedef struct PlatformDevtreeData { PlatformBusDevice *pbus; } PlatformDevtreeData; +static int create_devtree_etsec(SysBusDevice *sbdev, PlatformDevtreeData *data) +{ + eTSEC *etsec = ETSEC_COMMON(sbdev); + PlatformBusDevice *pbus = data->pbus; + hwaddr mmio0 = platform_bus_get_mmio_addr(pbus, sbdev, 0); + int irq0 = platform_bus_get_irqn(pbus, sbdev, 0); + int irq1 = platform_bus_get_irqn(pbus, sbdev, 1); + int irq2 = platform_bus_get_irqn(pbus, sbdev, 2); + gchar *node = g_strdup_printf("/platform/ethernet@%"PRIx64, mmio0); + gchar *group = g_strdup_printf("%s/queue-group", node); + void *fdt = data->fdt; + + assert((int64_t)mmio0 >= 0); + assert(irq0 >= 0); + assert(irq1 >= 0); + assert(irq2 >= 0); + + qemu_fdt_add_subnode(fdt, node); + qemu_fdt_setprop_string(fdt, node, "device_type", "network"); + qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,etsec2"); + qemu_fdt_setprop_string(fdt, node, "model", "eTSEC"); + qemu_fdt_setprop(fdt, node, "local-mac-address", etsec->conf.macaddr.a, 6); + qemu_fdt_setprop_cells(fdt, node, "fixed-link", 0, 1, 1000, 0, 0); + + qemu_fdt_add_subnode(fdt, group); + qemu_fdt_setprop_cells(fdt, group, "reg", mmio0, 0x1000); + qemu_fdt_setprop_cells(fdt, group, "interrupts", + data->irq_start + irq0, 0x2, + data->irq_start + irq1, 0x2, + data->irq_start + irq2, 0x2); + + g_free(node); + g_free(group); + + return 0; +} + static int sysbus_device_create_devtree(SysBusDevice *sbdev, void *opaque) { PlatformDevtreeData *data = opaque; bool matched = false; + if (object_dynamic_cast(OBJECT(sbdev), TYPE_ETSEC_COMMON)) { + create_devtree_etsec(sbdev, data); + matched = true; + } + if (!matched) { error_report("Device %s is not supported by this machine yet.", qdev_fw_name(DEVICE(sbdev))); From 36cbde7c30ead127dcd7c03b96d4dabf10a6d6c5 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 27 Oct 2014 17:25:52 +0100 Subject: [PATCH 30/34] target-ppc: simplify AES emulation This patch simplifies the AES code, by directly accessing the newly added S-Box, InvS-Box tables instead of recreating them by using the AES_Te and AES_Td tables. Cc: Alexander Graf Cc: Paolo Bonzini Signed-off-by: Aurelien Jarno Reviewed-by: Paolo Bonzini Tested-by: Tom Musta Signed-off-by: Alexander Graf --- target-ppc/int_helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index 83c1ad0654..1c7e0f1f77 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -2352,7 +2352,7 @@ void helper_vcipherlast(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) int i; VECTOR_FOR_INORDER_I(i, u8) { - r->AVRB(i) = b->AVRB(i) ^ (AES_Te4[a->AVRB(AES_shifts[i])] & 0xFF); + r->AVRB(i) = b->AVRB(i) ^ (AES_sbox[a->AVRB(AES_shifts[i])]); } } @@ -2381,7 +2381,7 @@ void helper_vncipherlast(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) int i; VECTOR_FOR_INORDER_I(i, u8) { - r->AVRB(i) = b->AVRB(i) ^ (AES_Td4[a->AVRB(AES_ishifts[i])] & 0xFF); + r->AVRB(i) = b->AVRB(i) ^ (AES_isbox[a->AVRB(AES_ishifts[i])]); } } From 24e669ba531a0ffb5e5c3583bc39ff84eaeabf16 Mon Sep 17 00:00:00 2001 From: Tom Musta Date: Wed, 29 Oct 2014 10:02:39 -0500 Subject: [PATCH 31/34] target-ppc: Fix Altivec Shifts Fix the implementation of the Altivec shift left and shift right instructions (vsl, vsr) which erroneously inverts shift direction on big endian hosts. Signed-off-by: Tom Musta Signed-off-by: Alexander Graf --- target-ppc/int_helper.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index 1c7e0f1f77..12c9ab08be 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -1552,13 +1552,6 @@ void helper_vlogefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b) } } -#if defined(HOST_WORDS_BIGENDIAN) -#define LEFT 0 -#define RIGHT 1 -#else -#define LEFT 1 -#define RIGHT 0 -#endif /* The specification says that the results are undefined if all of the * shift counts are not identical. We check to make sure that they are * to conform to what real hardware appears to do. */ @@ -1588,11 +1581,9 @@ void helper_vlogefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b) } \ } \ } -VSHIFT(l, LEFT) -VSHIFT(r, RIGHT) +VSHIFT(l, 1) +VSHIFT(r, 0) #undef VSHIFT -#undef LEFT -#undef RIGHT #define VSL(suffix, element, mask) \ void helper_vsl##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ From 4007b8de6e1012675672d6e6e4fc08633b3a0023 Mon Sep 17 00:00:00 2001 From: Tom Musta Date: Fri, 31 Oct 2014 11:39:54 -0500 Subject: [PATCH 32/34] target-ppc: Fix vcmpbfp. Unordered Case Fix the implementation of Vector Compare Bounds Single Precision. Specifically, fix the case where the operands are unordered -- since the result is non-zero, the CR[6] field should be set to zero. Signed-off-by: Tom Musta Signed-off-by: Alexander Graf --- target-ppc/int_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index 12c9ab08be..4c2b71c708 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -708,7 +708,7 @@ static inline void vcmpbfp_internal(CPUPPCState *env, ppc_avr_t *r, int le_rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status); if (le_rel == float_relation_unordered) { r->u32[i] = 0xc0000000; - /* ALL_IN does not need to be updated here. */ + all_in = 1; } else { float32 bneg = float32_chs(b->f[i]); int ge_rel = float32_compare_quiet(a->f[i], bneg, &env->vec_status); From abe60a439b760c749201b6b9956968d6f030ebd7 Mon Sep 17 00:00:00 2001 From: Tom Musta Date: Fri, 31 Oct 2014 11:06:15 -0500 Subject: [PATCH 33/34] target-ppc: Fix Altivec Round Opcodes Correct the opcodes for the vrfim, vrfin and vrfiz instructions. Signed-off-by: Tom Musta Reviewed-by: Thomas Huth Signed-off-by: Alexander Graf --- target-ppc/translate.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index f0567f7aec..910ce56ec1 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -7238,10 +7238,10 @@ GEN_VXFORM_NOA_ENV(vrefp, 5, 4); GEN_VXFORM_NOA_ENV(vrsqrtefp, 5, 5); GEN_VXFORM_NOA_ENV(vexptefp, 5, 6); GEN_VXFORM_NOA_ENV(vlogefp, 5, 7); -GEN_VXFORM_NOA_ENV(vrfim, 5, 8); -GEN_VXFORM_NOA_ENV(vrfin, 5, 9); +GEN_VXFORM_NOA_ENV(vrfim, 5, 11); +GEN_VXFORM_NOA_ENV(vrfin, 5, 8); GEN_VXFORM_NOA_ENV(vrfip, 5, 10); -GEN_VXFORM_NOA_ENV(vrfiz, 5, 11); +GEN_VXFORM_NOA_ENV(vrfiz, 5, 9); #define GEN_VXFORM_SIMM(name, opc2, opc3) \ static void glue(gen_, name)(DisasContext *ctx) \ @@ -10474,10 +10474,10 @@ GEN_VXFORM_NOA(vrefp, 5, 4), GEN_VXFORM_NOA(vrsqrtefp, 5, 5), GEN_VXFORM_NOA(vexptefp, 5, 6), GEN_VXFORM_NOA(vlogefp, 5, 7), -GEN_VXFORM_NOA(vrfim, 5, 8), -GEN_VXFORM_NOA(vrfin, 5, 9), +GEN_VXFORM_NOA(vrfim, 5, 11), +GEN_VXFORM_NOA(vrfin, 5, 8), GEN_VXFORM_NOA(vrfip, 5, 10), -GEN_VXFORM_NOA(vrfiz, 5, 11), +GEN_VXFORM_NOA(vrfiz, 5, 9), #undef GEN_VXFORM_UIMM #define GEN_VXFORM_UIMM(name, opc2, opc3) \ From 9e3f973335afb3d5758aeebeb3ad478427d79bd4 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 4 Nov 2014 23:22:54 +0100 Subject: [PATCH 34/34] spapr: Allow dynamic creation of PHB Now that we finally check for presence of dangling sysbus devices, make check started complaining that the sPAPR PHB is one such device. However, it really isn't. The spapr PHB is not really a traditional sysbus device, but much more a special spapr pv device which is already able to get created dynamically. Move spapr to its own dynamic sysbus check handling and allow PHB devices to get allocated dynamically. Signed-off-by: Alexander Graf --- hw/ppc/spapr.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 2a7807578e..30de25de5c 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -850,11 +850,31 @@ static void spapr_reset_htab(sPAPREnvironment *spapr) } } +static int find_unknown_sysbus_device(SysBusDevice *sbdev, void *opaque) +{ + bool matched = false; + + if (object_dynamic_cast(OBJECT(sbdev), TYPE_SPAPR_PCI_HOST_BRIDGE)) { + matched = true; + } + + if (!matched) { + error_report("Device %s is not supported by this machine yet.", + qdev_fw_name(DEVICE(sbdev))); + exit(1); + } + + return 0; +} + static void ppc_spapr_reset(void) { PowerPCCPU *first_ppc_cpu; uint32_t rtas_limit; + /* Check for unknown sysbus devices */ + foreach_dynamic_sysbus_device(find_unknown_sysbus_device, NULL); + /* Reset the hash table & recalc the RMA */ spapr_reset_htab(spapr); @@ -1667,6 +1687,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) mc->no_parallel = 1; mc->default_boot_order = NULL; mc->kvm_type = spapr_kvm_type; + mc->has_dynamic_sysbus = true; fwc->get_dev_path = spapr_get_fw_dev_path; nc->nmi_monitor_handler = spapr_nmi;