diff options
45 files changed, 930 insertions, 179 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 76a0fdb2c4..9bca506365 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -620,6 +620,7 @@ S: Maintained F: hw/ppc/mac_oldworld.c F: hw/pci-host/grackle.c F: hw/misc/macio/ +F: hw/intc/heathrow_pic.c PReP L: qemu-devel@nongnu.org @@ -628,6 +629,7 @@ S: Odd Fixes F: hw/ppc/prep.c F: hw/pci-host/prep.[hc] F: hw/isa/pc87312.[hc] +F: pc-bios/ppc_rom.bin sPAPR M: David Gibson <david@gibson.dropbear.id.au> diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 14b6821a94..03e38039e8 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -546,6 +546,51 @@ static int spapr_populate_memory(sPAPRMachineState *spapr, void *fdt) return 0; } +/* Populate the "ibm,pa-features" property */ +static void spapr_populate_pa_features(CPUPPCState *env, void *fdt, int offset) +{ + uint8_t pa_features_206[] = { 6, 0, + 0xf6, 0x1f, 0xc7, 0x00, 0x80, 0xc0 }; + uint8_t pa_features_207[] = { 24, 0, + 0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x00, 0x00 }; + uint8_t *pa_features; + size_t pa_size; + + switch (env->mmu_model) { + case POWERPC_MMU_2_06: + case POWERPC_MMU_2_06a: + pa_features = pa_features_206; + pa_size = sizeof(pa_features_206); + break; + case POWERPC_MMU_2_07: + case POWERPC_MMU_2_07a: + pa_features = pa_features_207; + pa_size = sizeof(pa_features_207); + break; + default: + return; + } + + if (env->ci_large_pages) { + /* + * Note: we keep CI large pages off by default because a 64K capable + * guest provisioned with large pages might otherwise try to map a qemu + * framebuffer (or other kind of memory mapped PCI BAR) using 64K pages + * even if that qemu runs on a 4k host. + * We dd this bit back here if we are confident this is not an issue + */ + pa_features[3] |= 0x20; + } + if (kvmppc_has_cap_htm() && pa_size > 24) { + pa_features[24] |= 0x80; /* Transactional memory support */ + } + + _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size))); +} + static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset, sPAPRMachineState *spapr) { @@ -573,24 +618,6 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset, _FDT((fdt_setprop_cell(fdt, offset, "ibm,my-drc-index", drc_index))); } - /* Note: we keep CI large pages off for now because a 64K capable guest - * provisioned with large pages might otherwise try to map a qemu - * framebuffer (or other kind of memory mapped PCI BAR) using 64K pages - * even if that qemu runs on a 4k host. - * - * We can later add this bit back when we are confident this is not - * an issue (!HV KVM or 64K host) - */ - uint8_t pa_features_206[] = { 6, 0, - 0xf6, 0x1f, 0xc7, 0x00, 0x80, 0xc0 }; - uint8_t pa_features_207[] = { 24, 0, - 0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x80, 0x00, 0x80, 0x00, 0x80, 0x00 }; - uint8_t *pa_features; - size_t pa_size; - _FDT((fdt_setprop_cell(fdt, offset, "reg", index))); _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu"))); @@ -657,18 +684,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset, page_sizes_prop, page_sizes_prop_size))); } - /* Do the ibm,pa-features property, adjust it for ci-large-pages */ - if (env->mmu_model == POWERPC_MMU_2_06) { - pa_features = pa_features_206; - pa_size = sizeof(pa_features_206); - } else /* env->mmu_model == POWERPC_MMU_2_07 */ { - pa_features = pa_features_207; - pa_size = sizeof(pa_features_207); - } - if (env->ci_large_pages) { - pa_features[3] |= 0x20; - } - _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size))); + spapr_populate_pa_features(env, fdt, offset); _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", cs->cpu_index / vcpus_per_socket))); @@ -1759,7 +1775,7 @@ static void ppc_spapr_init(MachineState *machine) /* init CPUs */ if (machine->cpu_model == NULL) { - machine->cpu_model = kvm_enabled() ? "host" : "POWER7"; + machine->cpu_model = kvm_enabled() ? "host" : smc->tcg_default_cpu; } ppc_cpu_parse_features(machine->cpu_model); @@ -2386,6 +2402,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) mc->cpu_index_to_socket_id = spapr_cpu_index_to_socket_id; smc->dr_lmb_enabled = true; + smc->tcg_default_cpu = "POWER8"; mc->query_hotpluggable_cpus = spapr_query_hotpluggable_cpus; fwc->get_dev_path = spapr_get_fw_dev_path; nc->nmi_monitor_handler = spapr_nmi; @@ -2437,18 +2454,39 @@ static const TypeInfo spapr_machine_info = { type_init(spapr_machine_register_##suffix) /* + * pseries-2.8 + */ +static void spapr_machine_2_8_instance_options(MachineState *machine) +{ +} + +static void spapr_machine_2_8_class_options(MachineClass *mc) +{ + /* Defaults for the latest behaviour inherited from the base class */ +} + +DEFINE_SPAPR_MACHINE(2_8, "2.8", true); + +/* * pseries-2.7 */ +#define SPAPR_COMPAT_2_7 \ + HW_COMPAT_2_7 \ + static void spapr_machine_2_7_instance_options(MachineState *machine) { } static void spapr_machine_2_7_class_options(MachineClass *mc) { - /* Defaults for the latest behaviour inherited from the base class */ + sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc); + + spapr_machine_2_8_class_options(mc); + smc->tcg_default_cpu = "POWER7"; + SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_7); } -DEFINE_SPAPR_MACHINE(2_7, "2.7", true); +DEFINE_SPAPR_MACHINE(2_7, "2.7", false); /* * pseries-2.6 diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index 6f0533c342..35d1873b9f 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -92,20 +92,20 @@ char *spapr_get_cpu_core_type(const char *model) gchar **model_pieces = g_strsplit(model, ",", 2); core_type = g_strdup_printf("%s-%s", model_pieces[0], TYPE_SPAPR_CPU_CORE); - g_strfreev(model_pieces); /* Check whether it exists or whether we have to look up an alias name */ if (!object_class_by_name(core_type)) { const char *realmodel; g_free(core_type); - realmodel = ppc_cpu_lookup_alias(model); + core_type = NULL; + realmodel = ppc_cpu_lookup_alias(model_pieces[0]); if (realmodel) { - return spapr_get_cpu_core_type(realmodel); + core_type = spapr_get_cpu_core_type(realmodel); } - return NULL; } + g_strfreev(model_pieces); return core_type; } diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c index d8a2296b7b..6090a204a0 100644 --- a/hw/scsi/spapr_vscsi.c +++ b/hw/scsi/spapr_vscsi.c @@ -658,7 +658,7 @@ static void vscsi_process_login(VSCSIState *s, vscsi_req *req) struct srp_login_rsp *rsp = &iu->srp.login_rsp; uint64_t tag = iu->srp.rsp.tag; - trace_spapr_vscsi__process_login(); + trace_spapr_vscsi_process_login(); /* TODO handle case that requested size is wrong and * buffer format is wrong diff --git a/hw/scsi/trace-events b/hw/scsi/trace-events index d1995b84f8..4a2e5d66df 100644 --- a/hw/scsi/trace-events +++ b/hw/scsi/trace-events @@ -225,7 +225,7 @@ spapr_vscsi_command_complete_sense_data2(unsigned s8, unsigned s9, unsigned s10, spapr_vscsi_command_complete_status(uint32_t status) "Command complete err=%"PRIu32 spapr_vscsi_save_request(uint32_t qtag, unsigned desc, unsigned offset) "saving tag=%"PRIu32", current desc#%u, offset=0x%x" spapr_vscsi_load_request(uint32_t qtag, unsigned desc, unsigned offset) "restoring tag=%"PRIu32", current desc#%u, offset=0x%x" -spapr_vscsi__process_login(void) "Got login, sending response !" +spapr_vscsi_process_login(void) "Got login, sending response !" spapr_vscsi_queue_cmd_no_drive(uint64_t lun) "Command for lun %08" PRIx64 " with no drive" spapr_vscsi_queue_cmd(uint32_t qtag, unsigned cdb, const char *cmd, int lun, int ret) "Queued command tag 0x%"PRIx32" CMD 0x%x=%s LUN %d ret: %d" spapr_vscsi_do_crq(unsigned c0, unsigned c1) "crq: %02x %02x ..." diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 6289d50dbf..39dadaa9ce 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -39,6 +39,7 @@ struct sPAPRMachineClass { /*< public >*/ bool dr_lmb_enabled; /* enable dynamic-reconfig/hotplug of LMBs */ bool use_ohci_by_default; /* use USB-OHCI instead of XHCI */ + const char *tcg_default_cpu; /* which (TCG) CPU to simulate by default */ }; /** diff --git a/target-ppc/helper.h b/target-ppc/helper.h index a1c29628bd..796ad455f8 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -147,6 +147,9 @@ DEF_HELPER_4(vcmpequb, void, env, avr, avr, avr) DEF_HELPER_4(vcmpequh, void, env, avr, avr, avr) DEF_HELPER_4(vcmpequw, void, env, avr, avr, avr) DEF_HELPER_4(vcmpequd, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpneb, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpneh, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpnew, void, env, avr, avr, avr) DEF_HELPER_4(vcmpnezb, void, env, avr, avr, avr) DEF_HELPER_4(vcmpnezh, void, env, avr, avr, avr) DEF_HELPER_4(vcmpnezw, void, env, avr, avr, avr) @@ -166,6 +169,9 @@ DEF_HELPER_4(vcmpequb_dot, void, env, avr, avr, avr) DEF_HELPER_4(vcmpequh_dot, void, env, avr, avr, avr) DEF_HELPER_4(vcmpequw_dot, void, env, avr, avr, avr) DEF_HELPER_4(vcmpequd_dot, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpneb_dot, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpneh_dot, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpnew_dot, void, env, avr, avr, avr) DEF_HELPER_4(vcmpnezb_dot, void, env, avr, avr, avr) DEF_HELPER_4(vcmpnezh_dot, void, env, avr, avr, avr) DEF_HELPER_4(vcmpnezw_dot, void, env, avr, avr, avr) @@ -337,6 +343,8 @@ DEF_HELPER_2(vpopcntb, void, avr, avr) DEF_HELPER_2(vpopcnth, void, avr, avr) DEF_HELPER_2(vpopcntw, void, avr, avr) DEF_HELPER_2(vpopcntd, void, avr, avr) +DEF_HELPER_1(vclzlsbb, tl, avr) +DEF_HELPER_1(vctzlsbb, tl, avr) DEF_HELPER_3(vbpermd, void, avr, avr, avr) DEF_HELPER_3(vbpermq, void, avr, avr, avr) DEF_HELPER_2(vgbbd, void, avr, avr) diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index 51a9ac5182..202854fabd 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -735,20 +735,24 @@ VCMP(gtsd, >, s64) #undef VCMP_DO #undef VCMP -#define VCMPNEZ_DO(suffix, element, etype, record) \ -void helper_vcmpnez##suffix(CPUPPCState *env, ppc_avr_t *r, \ +#define VCMPNE_DO(suffix, element, etype, cmpzero, record) \ +void helper_vcmpne##suffix(CPUPPCState *env, ppc_avr_t *r, \ ppc_avr_t *a, ppc_avr_t *b) \ { \ etype ones = (etype)-1; \ etype all = ones; \ - etype none = 0; \ + etype result, none = 0; \ int i; \ \ for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ - etype result = ((a->element[i] == 0) \ + if (cmpzero) { \ + result = ((a->element[i] == 0) \ || (b->element[i] == 0) \ || (a->element[i] != b->element[i]) ? \ ones : 0x0); \ + } else { \ + result = (a->element[i] != b->element[i]) ? ones : 0x0; \ + } \ r->element[i] = result; \ all &= result; \ none |= result; \ @@ -762,14 +766,17 @@ void helper_vcmpnez##suffix(CPUPPCState *env, ppc_avr_t *r, \ * suffix - instruction mnemonic suffix (b: byte, h: halfword, w: word) * element - element type to access from vector */ -#define VCMPNEZ(suffix, element, etype) \ - VCMPNEZ_DO(suffix, element, etype, 0) \ - VCMPNEZ_DO(suffix##_dot, element, etype, 1) -VCMPNEZ(b, u8, uint8_t) -VCMPNEZ(h, u16, uint16_t) -VCMPNEZ(w, u32, uint32_t) -#undef VCMPNEZ_DO -#undef VCMPNEZ +#define VCMPNE(suffix, element, etype, cmpzero) \ + VCMPNE_DO(suffix, element, etype, cmpzero, 0) \ + VCMPNE_DO(suffix##_dot, element, etype, cmpzero, 1) +VCMPNE(zb, u8, uint8_t, 1) +VCMPNE(zh, u16, uint16_t, 1) +VCMPNE(zw, u32, uint32_t, 1) +VCMPNE(b, u8, uint8_t, 0) +VCMPNE(h, u16, uint16_t, 0) +VCMPNE(w, u32, uint32_t, 0) +#undef VCMPNE_DO +#undef VCMPNE #define VCMPFP_DO(suffix, compare, order, record) \ void helper_vcmp##suffix(CPUPPCState *env, ppc_avr_t *r, \ @@ -874,6 +881,36 @@ VCT(uxs, cvtsduw, u32) VCT(sxs, cvtsdsw, s32) #undef VCT +target_ulong helper_vclzlsbb(ppc_avr_t *r) +{ + target_ulong count = 0; + int i; + VECTOR_FOR_INORDER_I(i, u8) { + if (r->u8[i] & 0x01) { + break; + } + count++; + } + return count; +} + +target_ulong helper_vctzlsbb(ppc_avr_t *r) +{ + target_ulong count = 0; + int i; +#if defined(HOST_WORDS_BIGENDIAN) + for (i = ARRAY_SIZE(r->u8) - 1; i >= 0; i--) { +#else + for (i = 0; i < ARRAY_SIZE(r->u8); i++) { +#endif + if (r->u8[i] & 0x01) { + break; + } + count++; + } + return count; +} + void helper_vmhaddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index a18d4d5654..9c4834c4fc 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -80,6 +80,7 @@ static int cap_ppc_watchdog; static int cap_papr; static int cap_htab_fd; static int cap_fixup_hcalls; +static int cap_htm; /* Hardware transactional memory support */ static uint32_t debug_inst_opcode; @@ -101,6 +102,16 @@ static void kvm_kick_cpu(void *opaque) qemu_cpu_kick(CPU(cpu)); } +/* Check whether we are running with KVM-PR (instead of KVM-HV). This + * should only be used for fallback tests - generally we should use + * explicit capabilities for the features we want, rather than + * assuming what is/isn't available depending on the KVM variant. */ +static bool kvmppc_is_pr(KVMState *ks) +{ + /* Assume KVM-PR if the GET_PVINFO capability is available */ + return kvm_check_extension(ks, KVM_CAP_PPC_GET_PVINFO) != 0; +} + static int kvm_ppc_register_host_cpu_type(void); int kvm_arch_init(MachineState *ms, KVMState *s) @@ -122,6 +133,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s) * only activated after this by kvmppc_set_papr() */ cap_htab_fd = kvm_check_extension(s, KVM_CAP_PPC_HTAB_FD); cap_fixup_hcalls = kvm_check_extension(s, KVM_CAP_PPC_FIXUP_HCALL); + cap_htm = kvm_vm_check_extension(s, KVM_CAP_PPC_HTM); if (!cap_interrupt_level) { fprintf(stderr, "KVM: Couldn't find level irq capability. Expect the " @@ -221,10 +233,9 @@ static void kvm_get_fallback_smmu_info(PowerPCCPU *cpu, * * For that to work we make a few assumptions: * - * - If KVM_CAP_PPC_GET_PVINFO is supported we are running "PR" - * KVM which only supports 4K and 16M pages, but supports them - * regardless of the backing store characteritics. We also don't - * support 1T segments. + * - Check whether we are running "PR" KVM which only supports 4K + * and 16M pages, but supports them regardless of the backing + * store characteritics. We also don't support 1T segments. * * This is safe as if HV KVM ever supports that capability or PR * KVM grows supports for more page/segment sizes, those versions @@ -239,7 +250,7 @@ static void kvm_get_fallback_smmu_info(PowerPCCPU *cpu, * implements KVM_CAP_PPC_GET_SMMU_INFO and thus doesn't hit * this fallback. */ - if (kvm_check_extension(cs->kvm_state, KVM_CAP_PPC_GET_PVINFO)) { + if (kvmppc_is_pr(cs->kvm_state)) { /* No flags */ info->flags = 0; info->slb_size = 64; @@ -559,11 +570,18 @@ int kvm_arch_init_vcpu(CPUState *cs) idle_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, kvm_kick_cpu, cpu); - /* Some targets support access to KVM's guest TLB. */ switch (cenv->mmu_model) { case POWERPC_MMU_BOOKE206: + /* This target supports access to KVM's guest TLB */ ret = kvm_booke206_tlb_init(cpu); break; + case POWERPC_MMU_2_07: + if (!cap_htm && !kvmppc_is_pr(cs->kvm_state)) { + /* KVM-HV has transactional memory on POWER8 also without the + * KVM_CAP_PPC_HTM extension, so enable it here instead. */ + cap_htm = true; + } + break; default: break; } @@ -2268,11 +2286,8 @@ int kvmppc_reset_htab(int shift_hint) /* We have a kernel that predates the htab reset calls. For PR * KVM, we need to allocate the htab ourselves, for an HV KVM of - * this era, it has allocated a 16MB fixed size hash table - * already. Kernels of this era have the GET_PVINFO capability - * only on PR, so we use this hack to determine the right - * answer */ - if (kvm_check_extension(kvm_state, KVM_CAP_PPC_GET_PVINFO)) { + * this era, it has allocated a 16MB fixed size hash table already. */ + if (kvmppc_is_pr(kvm_state)) { /* PR - tell caller to allocate htab */ return 0; } else { @@ -2353,6 +2368,11 @@ bool kvmppc_has_cap_fixup_hcalls(void) return cap_fixup_hcalls; } +bool kvmppc_has_cap_htm(void) +{ + return cap_htm; +} + static PowerPCCPUClass *ppc_cpu_get_family_class(PowerPCCPUClass *pcc) { ObjectClass *oc = OBJECT_CLASS(pcc); diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index a778184567..bd1d78bfbe 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -55,6 +55,7 @@ void kvmppc_hash64_free_pteg(uint64_t token); void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong pte_index, target_ulong pte0, target_ulong pte1); bool kvmppc_has_cap_fixup_hcalls(void); +bool kvmppc_has_cap_htm(void); int kvmppc_enable_hwrng(void); int kvmppc_put_books_sregs(PowerPCCPU *cpu); PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void); @@ -249,6 +250,11 @@ static inline bool kvmppc_has_cap_fixup_hcalls(void) abort(); } +static inline bool kvmppc_has_cap_htm(void) +{ + return false; +} + static inline int kvmppc_enable_hwrng(void) { return -1; diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 8eefd8231d..dab8f19a91 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -6203,7 +6203,7 @@ static opcode_t opcodes[] = { GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE), GEN_HANDLER(cmp, 0x1F, 0x00, 0x00, 0x00400000, PPC_INTEGER), GEN_HANDLER(cmpi, 0x0B, 0xFF, 0xFF, 0x00400000, PPC_INTEGER), -GEN_HANDLER(cmpl, 0x1F, 0x00, 0x01, 0x00400000, PPC_INTEGER), +GEN_HANDLER(cmpl, 0x1F, 0x00, 0x01, 0x00400001, PPC_INTEGER), GEN_HANDLER(cmpli, 0x0A, 0xFF, 0xFF, 0x00400000, PPC_INTEGER), #if defined(TARGET_PPC64) GEN_HANDLER_E(cmpeqb, 0x1F, 0x00, 0x07, 0x00600000, PPC_NONE, PPC2_ISA300), @@ -6297,7 +6297,7 @@ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW), GEN_HANDLER(bc, 0x10, 0xFF, 0xFF, 0x00000000, PPC_FLOW), GEN_HANDLER(bcctr, 0x13, 0x10, 0x10, 0x00000000, PPC_FLOW), GEN_HANDLER(bclr, 0x13, 0x10, 0x00, 0x00000000, PPC_FLOW), -GEN_HANDLER_E(bctar, 0x13, 0x10, 0x11, 0, PPC_NONE, PPC2_BCTAR_ISA207), +GEN_HANDLER_E(bctar, 0x13, 0x10, 0x11, 0x0000E000, PPC_NONE, PPC2_BCTAR_ISA207), GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER), GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW), #if defined(TARGET_PPC64) diff --git a/target-ppc/translate/vmx-impl.inc.c b/target-ppc/translate/vmx-impl.inc.c index 3ce374d891..25cd0735ac 100644 --- a/target-ppc/translate/vmx-impl.inc.c +++ b/target-ppc/translate/vmx-impl.inc.c @@ -510,7 +510,16 @@ GEN_VXRFORM(vcmpeqfp, 3, 3) GEN_VXRFORM(vcmpgefp, 3, 7) GEN_VXRFORM(vcmpgtfp, 3, 11) GEN_VXRFORM(vcmpbfp, 3, 15) - +GEN_VXRFORM(vcmpneb, 3, 0) +GEN_VXRFORM(vcmpneh, 3, 1) +GEN_VXRFORM(vcmpnew, 3, 2) + +GEN_VXRFORM_DUAL(vcmpequb, PPC_ALTIVEC, PPC_NONE, \ + vcmpneb, PPC_NONE, PPC2_ISA300) +GEN_VXRFORM_DUAL(vcmpequh, PPC_ALTIVEC, PPC_NONE, \ + vcmpneh, PPC_NONE, PPC2_ISA300) +GEN_VXRFORM_DUAL(vcmpequw, PPC_ALTIVEC, PPC_NONE, \ + vcmpnew, PPC_NONE, PPC2_ISA300) GEN_VXRFORM_DUAL(vcmpeqfp, PPC_ALTIVEC, PPC_NONE, \ vcmpequd, PPC_NONE, PPC2_ALTIVEC_207) GEN_VXRFORM_DUAL(vcmpbfp, PPC_ALTIVEC, PPC_NONE, \ @@ -584,6 +593,18 @@ static void glue(gen_, name)(DisasContext *ctx) \ tcg_temp_free_ptr(rd); \ } +#define GEN_VXFORM_NOA_3(name, opc2, opc3, opc4) \ +static void glue(gen_, name)(DisasContext *ctx) \ + { \ + TCGv_ptr rb; \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + rb = gen_avr_ptr(rB(ctx->opcode)); \ + gen_helper_##name(cpu_gpr[rD(ctx->opcode)], rb); \ + tcg_temp_free_ptr(rb); \ + } GEN_VXFORM_NOA(vupkhsb, 7, 8); GEN_VXFORM_NOA(vupkhsh, 7, 9); GEN_VXFORM_NOA(vupkhsw, 7, 25); @@ -691,18 +712,18 @@ GEN_VXFORM_UIMM_ENV(vcfux, 5, 12); GEN_VXFORM_UIMM_ENV(vcfsx, 5, 13); GEN_VXFORM_UIMM_ENV(vctuxs, 5, 14); GEN_VXFORM_UIMM_ENV(vctsxs, 5, 15); -GEN_VXFORM_DUAL(vspltb, PPC_NONE, PPC2_ALTIVEC_207, - vextractub, PPC_NONE, PPC2_ISA300); -GEN_VXFORM_DUAL(vsplth, PPC_NONE, PPC2_ALTIVEC_207, - vextractuh, PPC_NONE, PPC2_ISA300); -GEN_VXFORM_DUAL(vspltw, PPC_NONE, PPC2_ALTIVEC_207, - vextractuw, PPC_NONE, PPC2_ISA300); -GEN_VXFORM_DUAL(vspltisb, PPC_NONE, PPC2_ALTIVEC_207, - vinsertb, PPC_NONE, PPC2_ISA300); -GEN_VXFORM_DUAL(vspltish, PPC_NONE, PPC2_ALTIVEC_207, - vinserth, PPC_NONE, PPC2_ISA300); -GEN_VXFORM_DUAL(vspltisw, PPC_NONE, PPC2_ALTIVEC_207, - vinsertw, PPC_NONE, PPC2_ISA300); +GEN_VXFORM_DUAL(vspltb, PPC_ALTIVEC, PPC_NONE, + vextractub, PPC_NONE, PPC2_ISA300); +GEN_VXFORM_DUAL(vsplth, PPC_ALTIVEC, PPC_NONE, + vextractuh, PPC_NONE, PPC2_ISA300); +GEN_VXFORM_DUAL(vspltw, PPC_ALTIVEC, PPC_NONE, + vextractuw, PPC_NONE, PPC2_ISA300); +GEN_VXFORM_DUAL(vspltisb, PPC_ALTIVEC, PPC_NONE, + vinsertb, PPC_NONE, PPC2_ISA300); +GEN_VXFORM_DUAL(vspltish, PPC_ALTIVEC, PPC_NONE, + vinserth, PPC_NONE, PPC2_ISA300); +GEN_VXFORM_DUAL(vspltisw, PPC_ALTIVEC, PPC_NONE, + vinsertw, PPC_NONE, PPC2_ISA300); static void gen_vsldoi(DisasContext *ctx) { @@ -798,6 +819,8 @@ GEN_VXFORM_NOA_2(vctzb, 1, 24, 28) GEN_VXFORM_NOA_2(vctzh, 1, 24, 29) GEN_VXFORM_NOA_2(vctzw, 1, 24, 30) GEN_VXFORM_NOA_2(vctzd, 1, 24, 31) +GEN_VXFORM_NOA_3(vclzlsbb, 1, 24, 0) +GEN_VXFORM_NOA_3(vctzlsbb, 1, 24, 1) GEN_VXFORM_NOA(vpopcntb, 1, 28) GEN_VXFORM_NOA(vpopcnth, 1, 29) GEN_VXFORM_NOA(vpopcntw, 1, 30) diff --git a/target-ppc/translate/vmx-ops.inc.c b/target-ppc/translate/vmx-ops.inc.c index a7022a0de5..ac1dc9b2b2 100644 --- a/target-ppc/translate/vmx-ops.inc.c +++ b/target-ppc/translate/vmx-ops.inc.c @@ -181,9 +181,6 @@ GEN_HANDLER2_E(name, str, 0x4, opc2, opc3, 0x00000000, PPC_NONE, PPC2_ISA300), GEN_VXRFORM1_300(name, name, #name, opc2, opc3) \ GEN_VXRFORM1_300(name##_dot, name##_, #name ".", opc2, (opc3 | (0x1 << 4))) -GEN_VXRFORM(vcmpequb, 3, 0) -GEN_VXRFORM(vcmpequh, 3, 1) -GEN_VXRFORM(vcmpequw, 3, 2) GEN_VXRFORM_300(vcmpnezb, 3, 4) GEN_VXRFORM_300(vcmpnezh, 3, 5) GEN_VXRFORM_300(vcmpnezw, 3, 6) @@ -197,28 +194,33 @@ GEN_VXRFORM_DUAL(vcmpeqfp, vcmpequd, 3, 3, PPC_ALTIVEC, PPC_NONE) GEN_VXRFORM(vcmpgefp, 3, 7) GEN_VXRFORM_DUAL(vcmpgtfp, vcmpgtud, 3, 11, PPC_ALTIVEC, PPC_NONE) GEN_VXRFORM_DUAL(vcmpbfp, vcmpgtsd, 3, 15, PPC_ALTIVEC, PPC_NONE) +GEN_VXRFORM_DUAL(vcmpequb, vcmpneb, 3, 0, PPC_ALTIVEC, PPC_NONE) +GEN_VXRFORM_DUAL(vcmpequh, vcmpneh, 3, 1, PPC_ALTIVEC, PPC_NONE) +GEN_VXRFORM_DUAL(vcmpequw, vcmpnew, 3, 2, PPC_ALTIVEC, PPC_NONE) #define GEN_VXFORM_DUAL_INV(name0, name1, opc2, opc3, inval0, inval1, type) \ GEN_OPCODE_DUAL(name0##_##name1, 0x04, opc2, opc3, inval0, inval1, type, \ PPC_NONE) GEN_VXFORM_DUAL_INV(vspltb, vextractub, 6, 8, 0x00000000, 0x100000, - PPC2_ALTIVEC_207), + PPC_ALTIVEC), GEN_VXFORM_DUAL_INV(vsplth, vextractuh, 6, 9, 0x00000000, 0x100000, - PPC2_ALTIVEC_207), + PPC_ALTIVEC), GEN_VXFORM_DUAL_INV(vspltw, vextractuw, 6, 10, 0x00000000, 0x100000, - PPC2_ALTIVEC_207), + PPC_ALTIVEC), GEN_VXFORM_300_EXT(vextractd, 6, 11, 0x100000), GEN_VXFORM_DUAL_INV(vspltisb, vinsertb, 6, 12, 0x00000000, 0x100000, - PPC2_ALTIVEC_207), + PPC_ALTIVEC), GEN_VXFORM_DUAL_INV(vspltish, vinserth, 6, 13, 0x00000000, 0x100000, - PPC2_ALTIVEC_207), + PPC_ALTIVEC), GEN_VXFORM_DUAL_INV(vspltisw, vinsertw, 6, 14, 0x00000000, 0x100000, - PPC2_ALTIVEC_207), + PPC_ALTIVEC), GEN_VXFORM_300_EXT(vinsertd, 6, 15, 0x100000), GEN_VXFORM_300_EO(vctzb, 0x01, 0x18, 0x1C), GEN_VXFORM_300_EO(vctzh, 0x01, 0x18, 0x1D), GEN_VXFORM_300_EO(vctzw, 0x01, 0x18, 0x1E), GEN_VXFORM_300_EO(vctzd, 0x01, 0x18, 0x1F), +GEN_VXFORM_300_EO(vclzlsbb, 0x01, 0x18, 0x0), +GEN_VXFORM_300_EO(vctzlsbb, 0x01, 0x18, 0x1), GEN_VXFORM_300(vpermr, 0x1D, 0xFF), #define GEN_VXFORM_NOA(name, opc2, opc3) \ diff --git a/target-ppc/translate/vsx-impl.inc.c b/target-ppc/translate/vsx-impl.inc.c index eee6052d03..23ec1e115c 100644 --- a/target-ppc/translate/vsx-impl.inc.c +++ b/target-ppc/translate/vsx-impl.inc.c @@ -75,7 +75,6 @@ static void gen_lxvdsx(DisasContext *ctx) static void gen_lxvw4x(DisasContext *ctx) { TCGv EA; - TCGv_i64 tmp; TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode)); TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode)); if (unlikely(!ctx->vsx_enabled)) { @@ -84,22 +83,95 @@ static void gen_lxvw4x(DisasContext *ctx) } gen_set_access_type(ctx, ACCESS_INT); EA = tcg_temp_new(); - tmp = tcg_temp_new_i64(); gen_addr_reg_index(ctx, EA); - gen_qemu_ld32u_i64(ctx, tmp, EA); - tcg_gen_addi_tl(EA, EA, 4); - gen_qemu_ld32u_i64(ctx, xth, EA); - tcg_gen_deposit_i64(xth, xth, tmp, 32, 32); + if (ctx->le_mode) { + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + + tcg_gen_qemu_ld_i64(t0, EA, ctx->mem_idx, MO_LEQ); + tcg_gen_shri_i64(t1, t0, 32); + tcg_gen_deposit_i64(xth, t1, t0, 32, 32); + tcg_gen_addi_tl(EA, EA, 8); + tcg_gen_qemu_ld_i64(t0, EA, ctx->mem_idx, MO_LEQ); + tcg_gen_shri_i64(t1, t0, 32); + tcg_gen_deposit_i64(xtl, t1, t0, 32, 32); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + } else { + tcg_gen_qemu_ld_i64(xth, EA, ctx->mem_idx, MO_BEQ); + tcg_gen_addi_tl(EA, EA, 8); + tcg_gen_qemu_ld_i64(xtl, EA, ctx->mem_idx, MO_BEQ); + } + tcg_temp_free(EA); +} + +static void gen_bswap16x8(TCGv_i64 outh, TCGv_i64 outl, + TCGv_i64 inh, TCGv_i64 inl) +{ + TCGv_i64 mask = tcg_const_i64(0x00FF00FF00FF00FF); + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + + /* outh = ((inh & mask) << 8) | ((inh >> 8) & mask) */ + tcg_gen_and_i64(t0, inh, mask); + tcg_gen_shli_i64(t0, t0, 8); + tcg_gen_shri_i64(t1, inh, 8); + tcg_gen_and_i64(t1, t1, mask); + tcg_gen_or_i64(outh, t0, t1); + + /* outl = ((inl & mask) << 8) | ((inl >> 8) & mask) */ + tcg_gen_and_i64(t0, inl, mask); + tcg_gen_shli_i64(t0, t0, 8); + tcg_gen_shri_i64(t1, inl, 8); + tcg_gen_and_i64(t1, t1, mask); + tcg_gen_or_i64(outl, t0, t1); + + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(mask); +} + +static void gen_lxvh8x(DisasContext *ctx) +{ + TCGv EA; + TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode)); + TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode)); + + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + gen_set_access_type(ctx, ACCESS_INT); + + EA = tcg_temp_new(); + gen_addr_reg_index(ctx, EA); + tcg_gen_qemu_ld_i64(xth, EA, ctx->mem_idx, MO_BEQ); + tcg_gen_addi_tl(EA, EA, 8); + tcg_gen_qemu_ld_i64(xtl, EA, ctx->mem_idx, MO_BEQ); + if (ctx->le_mode) { + gen_bswap16x8(xth, xtl, xth, xtl); + } + tcg_temp_free(EA); +} - tcg_gen_addi_tl(EA, EA, 4); - gen_qemu_ld32u_i64(ctx, tmp, EA); - tcg_gen_addi_tl(EA, EA, 4); - gen_qemu_ld32u_i64(ctx, xtl, EA); - tcg_gen_deposit_i64(xtl, xtl, tmp, 32, 32); +static void gen_lxvb16x(DisasContext *ctx) +{ + TCGv EA; + TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode)); + TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode)); + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + gen_set_access_type(ctx, ACCESS_INT); + EA = tcg_temp_new(); + gen_addr_reg_index(ctx, EA); + tcg_gen_qemu_ld_i64(xth, EA, ctx->mem_idx, MO_BEQ); + tcg_gen_addi_tl(EA, EA, 8); + tcg_gen_qemu_ld_i64(xtl, EA, ctx->mem_idx, MO_BEQ); tcg_temp_free(EA); - tcg_temp_free_i64(tmp); } #define VSX_STORE_SCALAR(name, operation) \ @@ -142,7 +214,8 @@ static void gen_stxvd2x(DisasContext *ctx) static void gen_stxvw4x(DisasContext *ctx) { - TCGv_i64 tmp; + TCGv_i64 xsh = cpu_vsrh(xS(ctx->opcode)); + TCGv_i64 xsl = cpu_vsrl(xS(ctx->opcode)); TCGv EA; if (unlikely(!ctx->vsx_enabled)) { gen_exception(ctx, POWERPC_EXCP_VSXU); @@ -151,21 +224,75 @@ static void gen_stxvw4x(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_INT); EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); - tmp = tcg_temp_new_i64(); + if (ctx->le_mode) { + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + + tcg_gen_shri_i64(t0, xsh, 32); + tcg_gen_deposit_i64(t1, t0, xsh, 32, 32); + tcg_gen_qemu_st_i64(t1, EA, ctx->mem_idx, MO_LEQ); + tcg_gen_addi_tl(EA, EA, 8); + tcg_gen_shri_i64(t0, xsl, 32); + tcg_gen_deposit_i64(t1, t0, xsl, 32, 32); + tcg_gen_qemu_st_i64(t1, EA, ctx->mem_idx, MO_LEQ); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + } else { + tcg_gen_qemu_st_i64(xsh, EA, ctx->mem_idx, MO_BEQ); + tcg_gen_addi_tl(EA, EA, 8); + tcg_gen_qemu_st_i64(xsl, EA, ctx->mem_idx, MO_BEQ); + } + tcg_temp_free(EA); +} - tcg_gen_shri_i64(tmp, cpu_vsrh(xS(ctx->opcode)), 32); - gen_qemu_st32_i64(ctx, tmp, EA); - tcg_gen_addi_tl(EA, EA, 4); - gen_qemu_st32_i64(ctx, cpu_vsrh(xS(ctx->opcode)), EA); +static void gen_stxvh8x(DisasContext *ctx) +{ + TCGv_i64 xsh = cpu_vsrh(xS(ctx->opcode)); + TCGv_i64 xsl = cpu_vsrl(xS(ctx->opcode)); + TCGv EA; - tcg_gen_shri_i64(tmp, cpu_vsrl(xS(ctx->opcode)), 32); - tcg_gen_addi_tl(EA, EA, 4); - gen_qemu_st32_i64(ctx, tmp, EA); - tcg_gen_addi_tl(EA, EA, 4); - gen_qemu_st32_i64(ctx, cpu_vsrl(xS(ctx->opcode)), EA); + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + gen_set_access_type(ctx, ACCESS_INT); + EA = tcg_temp_new(); + gen_addr_reg_index(ctx, EA); + if (ctx->le_mode) { + TCGv_i64 outh = tcg_temp_new_i64(); + TCGv_i64 outl = tcg_temp_new_i64(); + + gen_bswap16x8(outh, outl, xsh, xsl); + tcg_gen_qemu_st_i64(outh, EA, ctx->mem_idx, MO_BEQ); + tcg_gen_addi_tl(EA, EA, 8); + tcg_gen_qemu_st_i64(outl, EA, ctx->mem_idx, MO_BEQ); + tcg_temp_free_i64(outh); + tcg_temp_free_i64(outl); + } else { + tcg_gen_qemu_st_i64(xsh, EA, ctx->mem_idx, MO_BEQ); + tcg_gen_addi_tl(EA, EA, 8); + tcg_gen_qemu_st_i64(xsl, EA, ctx->mem_idx, MO_BEQ); + } + tcg_temp_free(EA); +} +static void gen_stxvb16x(DisasContext *ctx) +{ + TCGv_i64 xsh = cpu_vsrh(xS(ctx->opcode)); + TCGv_i64 xsl = cpu_vsrl(xS(ctx->opcode)); + TCGv EA; + + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + gen_set_access_type(ctx, ACCESS_INT); + EA = tcg_temp_new(); + gen_addr_reg_index(ctx, EA); + tcg_gen_qemu_st_i64(xsh, EA, ctx->mem_idx, MO_BEQ); + tcg_gen_addi_tl(EA, EA, 8); + tcg_gen_qemu_st_i64(xsl, EA, ctx->mem_idx, MO_BEQ); tcg_temp_free(EA); - tcg_temp_free_i64(tmp); } #define MV_VSRW(name, tcgop1, tcgop2, target, source) \ @@ -217,6 +344,65 @@ static void gen_##name(DisasContext *ctx) \ MV_VSRD(mfvsrd, cpu_gpr[rA(ctx->opcode)], cpu_vsrh(xS(ctx->opcode))) MV_VSRD(mtvsrd, cpu_vsrh(xT(ctx->opcode)), cpu_gpr[rA(ctx->opcode)]) +static void gen_mfvsrld(DisasContext *ctx) +{ + if (xS(ctx->opcode) < 32) { + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + } else { + if (unlikely(!ctx->altivec_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VPU); + return; + } + } + + tcg_gen_mov_i64(cpu_gpr[rA(ctx->opcode)], cpu_vsrl(xS(ctx->opcode))); +} + +static void gen_mtvsrdd(DisasContext *ctx) +{ + if (xT(ctx->opcode) < 32) { + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + } else { + if (unlikely(!ctx->altivec_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VPU); + return; + } + } + + if (!rA(ctx->opcode)) { + tcg_gen_movi_i64(cpu_vsrh(xT(ctx->opcode)), 0); + } else { + tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), cpu_gpr[rA(ctx->opcode)]); + } + + tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_gpr[rB(ctx->opcode)]); +} + +static void gen_mtvsrws(DisasContext *ctx) +{ + if (xT(ctx->opcode) < 32) { + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + } else { + if (unlikely(!ctx->altivec_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VPU); + return; + } + } + + tcg_gen_deposit_i64(cpu_vsrl(xT(ctx->opcode)), cpu_gpr[rA(ctx->opcode)], + cpu_gpr[rA(ctx->opcode)], 32, 32); + tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), cpu_vsrl(xT(ctx->opcode))); +} + #endif static void gen_xxpermdi(DisasContext *ctx) diff --git a/target-ppc/translate/vsx-ops.inc.c b/target-ppc/translate/vsx-ops.inc.c index 414b73bd10..10eb4b9470 100644 --- a/target-ppc/translate/vsx-ops.inc.c +++ b/target-ppc/translate/vsx-ops.inc.c @@ -7,6 +7,8 @@ GEN_HANDLER_E(lxsspx, 0x1F, 0x0C, 0x10, 0, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(lxvd2x, 0x1F, 0x0C, 0x1A, 0, PPC_NONE, PPC2_VSX), GEN_HANDLER_E(lxvdsx, 0x1F, 0x0C, 0x0A, 0, PPC_NONE, PPC2_VSX), GEN_HANDLER_E(lxvw4x, 0x1F, 0x0C, 0x18, 0, PPC_NONE, PPC2_VSX), +GEN_HANDLER_E(lxvh8x, 0x1F, 0x0C, 0x19, 0, PPC_NONE, PPC2_ISA300), +GEN_HANDLER_E(lxvb16x, 0x1F, 0x0C, 0x1B, 0, PPC_NONE, PPC2_ISA300), GEN_HANDLER_E(stxsdx, 0x1F, 0xC, 0x16, 0, PPC_NONE, PPC2_VSX), GEN_HANDLER_E(stxsibx, 0x1F, 0xD, 0x1C, 0, PPC_NONE, PPC2_ISA300), @@ -15,6 +17,8 @@ GEN_HANDLER_E(stxsiwx, 0x1F, 0xC, 0x04, 0, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(stxsspx, 0x1F, 0xC, 0x14, 0, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(stxvd2x, 0x1F, 0xC, 0x1E, 0, PPC_NONE, PPC2_VSX), GEN_HANDLER_E(stxvw4x, 0x1F, 0xC, 0x1C, 0, PPC_NONE, PPC2_VSX), +GEN_HANDLER_E(stxvh8x, 0x1F, 0x0C, 0x1D, 0, PPC_NONE, PPC2_ISA300), +GEN_HANDLER_E(stxvb16x, 0x1F, 0x0C, 0x1F, 0, PPC_NONE, PPC2_ISA300), GEN_HANDLER_E(mfvsrwz, 0x1F, 0x13, 0x03, 0x0000F800, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(mtvsrwa, 0x1F, 0x13, 0x06, 0x0000F800, PPC_NONE, PPC2_VSX207), @@ -22,6 +26,9 @@ GEN_HANDLER_E(mtvsrwz, 0x1F, 0x13, 0x07, 0x0000F800, PPC_NONE, PPC2_VSX207), #if defined(TARGET_PPC64) GEN_HANDLER_E(mfvsrd, 0x1F, 0x13, 0x01, 0x0000F800, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(mtvsrd, 0x1F, 0x13, 0x05, 0x0000F800, PPC_NONE, PPC2_VSX207), +GEN_HANDLER_E(mfvsrld, 0X1F, 0x13, 0x09, 0x0000F800, PPC_NONE, PPC2_ISA300), +GEN_HANDLER_E(mtvsrdd, 0X1F, 0x13, 0x0D, 0x0, PPC_NONE, PPC2_ISA300), +GEN_HANDLER_E(mtvsrws, 0x1F, 0x13, 0x0C, 0x0000F800, PPC_NONE, PPC2_ISA300), #endif #define GEN_XX1FORM(name, opc2, opc3, fl2) \ diff --git a/tests/Makefile.include b/tests/Makefile.include index 25aaae3c6e..a77777cf9c 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -271,6 +271,13 @@ check-qtest-ppc64-y += tests/drive_del-test$(EXESUF) check-qtest-ppc64-y += tests/postcopy-test$(EXESUF) check-qtest-ppc64-y += tests/boot-serial-test$(EXESUF) check-qtest-ppc64-y += tests/rtas-test$(EXESUF) +check-qtest-ppc64-y += tests/pxe-test$(EXESUF) +check-qtest-ppc64-y += tests/usb-hcd-ohci-test$(EXESUF) +gcov-files-ppc64-y += hw/usb/hcd-ohci.c +check-qtest-ppc64-y += tests/usb-hcd-uhci-test$(EXESUF) +gcov-files-ppc64-y += hw/usb/hcd-uhci.c +check-qtest-ppc64-y += tests/usb-hcd-xhci-test$(EXESUF) +gcov-files-ppc64-y += hw/usb/hcd-xhci.c check-qtest-sh4-y = tests/endianness-test$(EXESUF) @@ -590,12 +597,13 @@ libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o libqos-spapr-obj-y = $(libqos-obj-y) tests/libqos/malloc-spapr.o libqos-spapr-obj-y += tests/libqos/libqos-spapr.o libqos-spapr-obj-y += tests/libqos/rtas.o +libqos-spapr-obj-y += tests/libqos/pci-spapr.o libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o libqos-pc-obj-y += tests/libqos/ahci.o libqos-omap-obj-y = $(libqos-obj-y) tests/libqos/i2c-omap.o libqos-imx-obj-y = $(libqos-obj-y) tests/libqos/i2c-imx.o -libqos-usb-obj-y = $(libqos-pc-obj-y) tests/libqos/usb.o +libqos-usb-obj-y = $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos/usb.o libqos-virtio-obj-y = $(libqos-pc-obj-y) tests/libqos/virtio.o tests/libqos/virtio-pci.o tests/libqos/virtio-mmio.o tests/libqos/malloc-generic.o tests/device-introspect-test$(EXESUF): tests/device-introspect-test.o diff --git a/tests/boot-sector.c b/tests/boot-sector.c index 3ffe2987ff..e3193c0a12 100644 --- a/tests/boot-sector.c +++ b/tests/boot-sector.c @@ -77,6 +77,15 @@ int boot_sector_init(const char *fname) fprintf(stderr, "Couldn't open \"%s\": %s", fname, strerror(errno)); return 1; } + + /* For Open Firmware based system, we can use a Forth script instead */ + if (strcmp(qtest_get_arch(), "ppc64") == 0) { + memset(boot_sector, ' ', sizeof boot_sector); + sprintf((char *)boot_sector, "\\ Bootscript\n%x %x c! %x %x c!\n", + LOW(SIGNATURE), BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET, + HIGH(SIGNATURE), BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET + 1); + } + fwrite(boot_sector, 1, sizeof boot_sector, f); fclose(f); return 0; diff --git a/tests/e1000e-test.c b/tests/e1000e-test.c index d497b0857c..3979b20bb0 100644 --- a/tests/e1000e-test.c +++ b/tests/e1000e-test.c @@ -390,7 +390,7 @@ static void data_test_init(e1000e_device *d) qtest_start(cmdline); g_free(cmdline); - test_bus = qpci_init_pc(); + test_bus = qpci_init_pc(NULL); g_assert_nonnull(test_bus); test_alloc = pc_alloc_init(); diff --git a/tests/i440fx-test.c b/tests/i440fx-test.c index 3542ad114e..da2d5a53f0 100644 --- a/tests/i440fx-test.c +++ b/tests/i440fx-test.c @@ -38,7 +38,7 @@ static QPCIBus *test_start_get_bus(const TestData *s) cmdline = g_strdup_printf("-smp %d", s->num_cpus); qtest_start(cmdline); g_free(cmdline); - return qpci_init_pc(); + return qpci_init_pc(NULL); } static void test_i440fx_defaults(gconstpointer opaque) diff --git a/tests/ide-test.c b/tests/ide-test.c index 1e51af2a94..a8a4081f78 100644 --- a/tests/ide-test.c +++ b/tests/ide-test.c @@ -143,7 +143,7 @@ static QPCIDevice *get_pci_device(uint16_t *bmdma_base) uint16_t vendor_id, device_id; if (!pcibus) { - pcibus = qpci_init_pc(); + pcibus = qpci_init_pc(NULL); } /* Find PCI device and verify it's the right one */ diff --git a/tests/ivshmem-test.c b/tests/ivshmem-test.c index 0957ee7555..f36bfe7d0a 100644 --- a/tests/ivshmem-test.c +++ b/tests/ivshmem-test.c @@ -105,7 +105,7 @@ static void setup_vm_cmd(IVState *s, const char *cmd, bool msix) uint64_t barsize; s->qtest = qtest_start(cmd); - s->pcibus = qpci_init_pc(); + s->pcibus = qpci_init_pc(NULL); s->dev = get_device(s->pcibus); s->reg_base = qpci_iomap(s->dev, 0, &barsize); diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c index f3be5500e1..716ab7939e 100644 --- a/tests/libqos/ahci.c +++ b/tests/libqos/ahci.c @@ -128,7 +128,7 @@ QPCIDevice *get_ahci_device(uint32_t *fingerprint) uint32_t ahci_fingerprint; QPCIBus *pcibus; - pcibus = qpci_init_pc(); + pcibus = qpci_init_pc(NULL); /* Find the AHCI PCI device and verify it's the right one. */ ahci = qpci_device_find(pcibus, QPCI_DEVFN(0x1F, 0x02)); diff --git a/tests/libqos/libqos-pc.c b/tests/libqos/libqos-pc.c index df340928a6..b554758802 100644 --- a/tests/libqos/libqos-pc.c +++ b/tests/libqos/libqos-pc.c @@ -1,10 +1,14 @@ #include "qemu/osdep.h" #include "libqos/libqos-pc.h" #include "libqos/malloc-pc.h" +#include "libqos/pci-pc.h" static QOSOps qos_ops = { .init_allocator = pc_alloc_init_flags, - .uninit_allocator = pc_alloc_uninit + .uninit_allocator = pc_alloc_uninit, + .qpci_init = qpci_init_pc, + .qpci_free = qpci_free_pc, + .shutdown = qtest_pc_shutdown, }; QOSState *qtest_pc_vboot(const char *cmdline_fmt, va_list ap) @@ -28,5 +32,5 @@ QOSState *qtest_pc_boot(const char *cmdline_fmt, ...) void qtest_pc_shutdown(QOSState *qs) { - return qtest_shutdown(qs); + return qtest_common_shutdown(qs); } diff --git a/tests/libqos/libqos-spapr.c b/tests/libqos/libqos-spapr.c index f19408be00..a37791e5d0 100644 --- a/tests/libqos/libqos-spapr.c +++ b/tests/libqos/libqos-spapr.c @@ -1,10 +1,14 @@ #include "qemu/osdep.h" #include "libqos/libqos-spapr.h" #include "libqos/malloc-spapr.h" +#include "libqos/pci-spapr.h" static QOSOps qos_ops = { .init_allocator = spapr_alloc_init_flags, - .uninit_allocator = spapr_alloc_uninit + .uninit_allocator = spapr_alloc_uninit, + .qpci_init = qpci_init_spapr, + .qpci_free = qpci_free_spapr, + .shutdown = qtest_spapr_shutdown, }; QOSState *qtest_spapr_vboot(const char *cmdline_fmt, va_list ap) @@ -26,5 +30,5 @@ QOSState *qtest_spapr_boot(const char *cmdline_fmt, ...) void qtest_spapr_shutdown(QOSState *qs) { - return qtest_shutdown(qs); + return qtest_common_shutdown(qs); } diff --git a/tests/libqos/libqos.c b/tests/libqos/libqos.c index a852dc5f8e..7abb48254e 100644 --- a/tests/libqos/libqos.c +++ b/tests/libqos/libqos.c @@ -20,8 +20,13 @@ QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap) cmdline = g_strdup_vprintf(cmdline_fmt, ap); qs->qts = qtest_start(cmdline); qs->ops = ops; - if (ops && ops->init_allocator) { - qs->alloc = ops->init_allocator(ALLOC_NO_FLAGS); + if (ops) { + if (ops->init_allocator) { + qs->alloc = ops->init_allocator(ALLOC_NO_FLAGS); + } + if (ops->qpci_init && qs->alloc) { + qs->pcibus = ops->qpci_init(qs->alloc); + } } g_free(cmdline); @@ -47,16 +52,31 @@ QOSState *qtest_boot(QOSOps *ops, const char *cmdline_fmt, ...) /** * Tear down the QEMU instance. */ -void qtest_shutdown(QOSState *qs) +void qtest_common_shutdown(QOSState *qs) { - if (qs->alloc && qs->ops && qs->ops->uninit_allocator) { - qs->ops->uninit_allocator(qs->alloc); - qs->alloc = NULL; + if (qs->ops) { + if (qs->pcibus && qs->ops->qpci_free) { + qs->ops->qpci_free(qs->pcibus); + qs->pcibus = NULL; + } + if (qs->alloc && qs->ops->uninit_allocator) { + qs->ops->uninit_allocator(qs->alloc); + qs->alloc = NULL; + } } qtest_quit(qs->qts); g_free(qs); } +void qtest_shutdown(QOSState *qs) +{ + if (qs->ops && qs->ops->shutdown) { + qs->ops->shutdown(qs); + } else { + qtest_common_shutdown(qs); + } +} + void set_context(QOSState *s) { global_qtest = s->qts; diff --git a/tests/libqos/libqos.h b/tests/libqos/libqos.h index 604980d125..231969766f 100644 --- a/tests/libqos/libqos.h +++ b/tests/libqos/libqos.h @@ -5,19 +5,26 @@ #include "libqos/pci.h" #include "libqos/malloc-pc.h" +typedef struct QOSState QOSState; + typedef struct QOSOps { QGuestAllocator *(*init_allocator)(QAllocOpts); void (*uninit_allocator)(QGuestAllocator *); + QPCIBus *(*qpci_init)(QGuestAllocator *alloc); + void (*qpci_free)(QPCIBus *bus); + void (*shutdown)(QOSState *); } QOSOps; -typedef struct QOSState { +struct QOSState { QTestState *qts; QGuestAllocator *alloc; + QPCIBus *pcibus; QOSOps *ops; -} QOSState; +}; QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap); QOSState *qtest_boot(QOSOps *ops, const char *cmdline_fmt, ...); +void qtest_common_shutdown(QOSState *qs); void qtest_shutdown(QOSState *qs); bool have_qemu_img(void); void mkimg(const char *file, const char *fmt, unsigned size_mb); diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c index 1ae2d3780f..9600ed6e41 100644 --- a/tests/libqos/pci-pc.c +++ b/tests/libqos/pci-pc.c @@ -212,7 +212,7 @@ static void qpci_pc_iounmap(QPCIBus *bus, void *data) /* FIXME */ } -QPCIBus *qpci_init_pc(void) +QPCIBus *qpci_init_pc(QGuestAllocator *alloc) { QPCIBusPC *ret; @@ -255,28 +255,6 @@ void qpci_free_pc(QPCIBus *bus) g_free(s); } -void qpci_plug_device_test(const char *driver, const char *id, - uint8_t slot, const char *opts) -{ - QDict *response; - char *cmd; - - cmd = g_strdup_printf("{'execute': 'device_add'," - " 'arguments': {" - " 'driver': '%s'," - " 'addr': '%d'," - " %s%s" - " 'id': '%s'" - "}}", driver, slot, - opts ? opts : "", opts ? "," : "", - id); - response = qmp(cmd); - g_free(cmd); - g_assert(response); - g_assert(!qdict_haskey(response, "error")); - QDECREF(response); -} - void qpci_unplug_acpi_device_test(const char *id, uint8_t slot) { QDict *response; diff --git a/tests/libqos/pci-pc.h b/tests/libqos/pci-pc.h index 26211790cd..9479b51642 100644 --- a/tests/libqos/pci-pc.h +++ b/tests/libqos/pci-pc.h @@ -14,8 +14,9 @@ #define LIBQOS_PCI_PC_H #include "libqos/pci.h" +#include "libqos/malloc.h" -QPCIBus *qpci_init_pc(void); +QPCIBus *qpci_init_pc(QGuestAllocator *alloc); void qpci_free_pc(QPCIBus *bus); #endif diff --git a/tests/libqos/pci-spapr.c b/tests/libqos/pci-spapr.c new file mode 100644 index 0000000000..2f73badfd9 --- /dev/null +++ b/tests/libqos/pci-spapr.c @@ -0,0 +1,288 @@ +/* + * libqos PCI bindings for SPAPR + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "libqtest.h" +#include "libqos/pci-spapr.h" +#include "libqos/rtas.h" + +#include "hw/pci/pci_regs.h" + +#include "qemu-common.h" +#include "qemu/host-utils.h" + + +/* From include/hw/pci-host/spapr.h */ + +#define SPAPR_PCI_BASE_BUID 0x800000020000000ULL + +#define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL + +#define SPAPR_PCI_WINDOW_BASE 0x10000000000ULL +#define SPAPR_PCI_WINDOW_SPACING 0x1000000000ULL +#define SPAPR_PCI_MMIO_WIN_OFF 0xA0000000 +#define SPAPR_PCI_MMIO_WIN_SIZE (SPAPR_PCI_WINDOW_SPACING - \ + SPAPR_PCI_MEM_WIN_BUS_OFFSET) +#define SPAPR_PCI_IO_WIN_OFF 0x80000000 +#define SPAPR_PCI_IO_WIN_SIZE 0x10000 + +/* index is the phb index */ + +#define BUIDBASE(index) (SPAPR_PCI_BASE_BUID + (index)) +#define PCIBASE(index) (SPAPR_PCI_WINDOW_BASE + \ + (index) * SPAPR_PCI_WINDOW_SPACING) +#define IOBASE(index) (PCIBASE(index) + SPAPR_PCI_IO_WIN_OFF) +#define MMIOBASE(index) (PCIBASE(index) + SPAPR_PCI_MMIO_WIN_OFF) + +typedef struct QPCIBusSPAPR { + QPCIBus bus; + QGuestAllocator *alloc; + + uint64_t pci_hole_start; + uint64_t pci_hole_size; + uint64_t pci_hole_alloc; + + uint32_t pci_iohole_start; + uint32_t pci_iohole_size; + uint32_t pci_iohole_alloc; +} QPCIBusSPAPR; + +/* + * PCI devices are always little-endian + * SPAPR by default is big-endian + * so PCI accessors need to swap data endianness + */ + +static uint8_t qpci_spapr_io_readb(QPCIBus *bus, void *addr) +{ + uint64_t port = (uintptr_t)addr; + uint8_t v; + if (port < SPAPR_PCI_IO_WIN_SIZE) { + v = readb(IOBASE(0) + port); + } else { + v = readb(MMIOBASE(0) + port); + } + return v; +} + +static uint16_t qpci_spapr_io_readw(QPCIBus *bus, void *addr) +{ + uint64_t port = (uintptr_t)addr; + uint16_t v; + if (port < SPAPR_PCI_IO_WIN_SIZE) { + v = readw(IOBASE(0) + port); + } else { + v = readw(MMIOBASE(0) + port); + } + return bswap16(v); +} + +static uint32_t qpci_spapr_io_readl(QPCIBus *bus, void *addr) +{ + uint64_t port = (uintptr_t)addr; + uint32_t v; + if (port < SPAPR_PCI_IO_WIN_SIZE) { + v = readl(IOBASE(0) + port); + } else { + v = readl(MMIOBASE(0) + port); + } + return bswap32(v); +} + +static void qpci_spapr_io_writeb(QPCIBus *bus, void *addr, uint8_t value) +{ + uint64_t port = (uintptr_t)addr; + if (port < SPAPR_PCI_IO_WIN_SIZE) { + writeb(IOBASE(0) + port, value); + } else { + writeb(MMIOBASE(0) + port, value); + } +} + +static void qpci_spapr_io_writew(QPCIBus *bus, void *addr, uint16_t value) +{ + uint64_t port = (uintptr_t)addr; + value = bswap16(value); + if (port < SPAPR_PCI_IO_WIN_SIZE) { + writew(IOBASE(0) + port, value); + } else { + writew(MMIOBASE(0) + port, value); + } +} + +static void qpci_spapr_io_writel(QPCIBus *bus, void *addr, uint32_t value) +{ + uint64_t port = (uintptr_t)addr; + value = bswap32(value); + if (port < SPAPR_PCI_IO_WIN_SIZE) { + writel(IOBASE(0) + port, value); + } else { + writel(MMIOBASE(0) + port, value); + } +} + +static uint8_t qpci_spapr_config_readb(QPCIBus *bus, int devfn, uint8_t offset) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + uint32_t config_addr = (devfn << 8) | offset; + return qrtas_ibm_read_pci_config(s->alloc, BUIDBASE(0), + config_addr, 1); +} + +static uint16_t qpci_spapr_config_readw(QPCIBus *bus, int devfn, uint8_t offset) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + uint32_t config_addr = (devfn << 8) | offset; + return qrtas_ibm_read_pci_config(s->alloc, BUIDBASE(0), + config_addr, 2); +} + +static uint32_t qpci_spapr_config_readl(QPCIBus *bus, int devfn, uint8_t offset) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + uint32_t config_addr = (devfn << 8) | offset; + return qrtas_ibm_read_pci_config(s->alloc, BUIDBASE(0), + config_addr, 4); +} + +static void qpci_spapr_config_writeb(QPCIBus *bus, int devfn, uint8_t offset, + uint8_t value) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + uint32_t config_addr = (devfn << 8) | offset; + qrtas_ibm_write_pci_config(s->alloc, BUIDBASE(0), + config_addr, 1, value); +} + +static void qpci_spapr_config_writew(QPCIBus *bus, int devfn, uint8_t offset, + uint16_t value) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + uint32_t config_addr = (devfn << 8) | offset; + qrtas_ibm_write_pci_config(s->alloc, BUIDBASE(0), + config_addr, 2, value); +} + +static void qpci_spapr_config_writel(QPCIBus *bus, int devfn, uint8_t offset, + uint32_t value) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + uint32_t config_addr = (devfn << 8) | offset; + qrtas_ibm_write_pci_config(s->alloc, BUIDBASE(0), + config_addr, 4, value); +} + +static void *qpci_spapr_iomap(QPCIBus *bus, QPCIDevice *dev, int barno, + uint64_t *sizeptr) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + static const int bar_reg_map[] = { + PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2, + PCI_BASE_ADDRESS_3, PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5, + }; + int bar_reg; + uint32_t addr; + uint64_t size; + uint32_t io_type; + + g_assert(barno >= 0 && barno <= 5); + bar_reg = bar_reg_map[barno]; + + qpci_config_writel(dev, bar_reg, 0xFFFFFFFF); + addr = qpci_config_readl(dev, bar_reg); + + io_type = addr & PCI_BASE_ADDRESS_SPACE; + if (io_type == PCI_BASE_ADDRESS_SPACE_IO) { + addr &= PCI_BASE_ADDRESS_IO_MASK; + } else { + addr &= PCI_BASE_ADDRESS_MEM_MASK; + } + + size = (1ULL << ctzl(addr)); + if (size == 0) { + return NULL; + } + if (sizeptr) { + *sizeptr = size; + } + + if (io_type == PCI_BASE_ADDRESS_SPACE_IO) { + uint16_t loc; + + g_assert(QEMU_ALIGN_UP(s->pci_iohole_alloc, size) + size + <= s->pci_iohole_size); + s->pci_iohole_alloc = QEMU_ALIGN_UP(s->pci_iohole_alloc, size); + loc = s->pci_iohole_start + s->pci_iohole_alloc; + s->pci_iohole_alloc += size; + + qpci_config_writel(dev, bar_reg, loc | PCI_BASE_ADDRESS_SPACE_IO); + + return (void *)(unsigned long)loc; + } else { + uint64_t loc; + + g_assert(QEMU_ALIGN_UP(s->pci_hole_alloc, size) + size + <= s->pci_hole_size); + s->pci_hole_alloc = QEMU_ALIGN_UP(s->pci_hole_alloc, size); + loc = s->pci_hole_start + s->pci_hole_alloc; + s->pci_hole_alloc += size; + + qpci_config_writel(dev, bar_reg, loc); + + return (void *)(unsigned long)loc; + } +} + +static void qpci_spapr_iounmap(QPCIBus *bus, void *data) +{ + /* FIXME */ +} + +QPCIBus *qpci_init_spapr(QGuestAllocator *alloc) +{ + QPCIBusSPAPR *ret; + + ret = g_malloc(sizeof(*ret)); + + ret->alloc = alloc; + + ret->bus.io_readb = qpci_spapr_io_readb; + ret->bus.io_readw = qpci_spapr_io_readw; + ret->bus.io_readl = qpci_spapr_io_readl; + + ret->bus.io_writeb = qpci_spapr_io_writeb; + ret->bus.io_writew = qpci_spapr_io_writew; + ret->bus.io_writel = qpci_spapr_io_writel; + + ret->bus.config_readb = qpci_spapr_config_readb; + ret->bus.config_readw = qpci_spapr_config_readw; + ret->bus.config_readl = qpci_spapr_config_readl; + + ret->bus.config_writeb = qpci_spapr_config_writeb; + ret->bus.config_writew = qpci_spapr_config_writew; + ret->bus.config_writel = qpci_spapr_config_writel; + + ret->bus.iomap = qpci_spapr_iomap; + ret->bus.iounmap = qpci_spapr_iounmap; + + ret->pci_hole_start = 0xC0000000; + ret->pci_hole_size = SPAPR_PCI_MMIO_WIN_SIZE; + ret->pci_hole_alloc = 0; + + ret->pci_iohole_start = 0xc000; + ret->pci_iohole_size = SPAPR_PCI_IO_WIN_SIZE; + ret->pci_iohole_alloc = 0; + + return &ret->bus; +} + +void qpci_free_spapr(QPCIBus *bus) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + + g_free(s); +} diff --git a/tests/libqos/pci-spapr.h b/tests/libqos/pci-spapr.h new file mode 100644 index 0000000000..4192126d86 --- /dev/null +++ b/tests/libqos/pci-spapr.h @@ -0,0 +1,17 @@ +/* + * libqos PCI bindings for SPAPR + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef LIBQOS_PCI_SPAPR_H +#define LIBQOS_PCI_SPAPR_H + +#include "libqos/malloc.h" +#include "libqos/pci.h" + +QPCIBus *qpci_init_spapr(QGuestAllocator *alloc); +void qpci_free_spapr(QPCIBus *bus); + +#endif diff --git a/tests/libqos/pci.c b/tests/libqos/pci.c index ed78d91cea..c3f3382b7c 100644 --- a/tests/libqos/pci.c +++ b/tests/libqos/pci.c @@ -263,4 +263,24 @@ void qpci_iounmap(QPCIDevice *dev, void *data) dev->bus->iounmap(dev->bus, data); } - +void qpci_plug_device_test(const char *driver, const char *id, + uint8_t slot, const char *opts) +{ + QDict *response; + char *cmd; + + cmd = g_strdup_printf("{'execute': 'device_add'," + " 'arguments': {" + " 'driver': '%s'," + " 'addr': '%d'," + " %s%s" + " 'id': '%s'" + "}}", driver, slot, + opts ? opts : "", opts ? "," : "", + id); + response = qmp(cmd); + g_free(cmd); + g_assert(response); + g_assert(!qdict_haskey(response, "error")); + QDECREF(response); +} diff --git a/tests/libqos/rtas.c b/tests/libqos/rtas.c index 820321a3a7..0269803ce0 100644 --- a/tests/libqos/rtas.c +++ b/tests/libqos/rtas.c @@ -69,3 +69,48 @@ int qrtas_get_time_of_day(QGuestAllocator *alloc, struct tm *tm, uint32_t *ns) return res; } + +uint32_t qrtas_ibm_read_pci_config(QGuestAllocator *alloc, uint64_t buid, + uint32_t addr, uint32_t size) +{ + int res; + uint32_t args[4], ret[2]; + + args[0] = addr; + args[1] = buid >> 32; + args[2] = buid & 0xffffffff; + args[3] = size; + res = qrtas_call(alloc, "ibm,read-pci-config", 4, args, 2, ret); + if (res != 0) { + return -1; + } + + if (ret[0] != 0) { + return -1; + } + + return ret[1]; +} + +int qrtas_ibm_write_pci_config(QGuestAllocator *alloc, uint64_t buid, + uint32_t addr, uint32_t size, uint32_t val) +{ + int res; + uint32_t args[5], ret[1]; + + args[0] = addr; + args[1] = buid >> 32; + args[2] = buid & 0xffffffff; + args[3] = size; + args[4] = val; + res = qrtas_call(alloc, "ibm,write-pci-config", 5, args, 1, ret); + if (res != 0) { + return -1; + } + + if (ret[0] != 0) { + return -1; + } + + return 0; +} diff --git a/tests/libqos/rtas.h b/tests/libqos/rtas.h index a1b60a8eb4..498eb19230 100644 --- a/tests/libqos/rtas.h +++ b/tests/libqos/rtas.h @@ -8,4 +8,8 @@ #include "libqos/malloc.h" int qrtas_get_time_of_day(QGuestAllocator *alloc, struct tm *tm, uint32_t *ns); +uint32_t qrtas_ibm_read_pci_config(QGuestAllocator *alloc, uint64_t buid, + uint32_t addr, uint32_t size); +int qrtas_ibm_write_pci_config(QGuestAllocator *alloc, uint64_t buid, + uint32_t addr, uint32_t size, uint32_t val); #endif /* LIBQOS_RTAS_H */ diff --git a/tests/pxe-test.c b/tests/pxe-test.c index b2cc355a95..5d3ddbe5e9 100644 --- a/tests/pxe-test.c +++ b/tests/pxe-test.c @@ -21,14 +21,14 @@ static const char *disk = "tests/pxe-test-disk.raw"; -static void test_pxe_one(const char *params) +static void test_pxe_one(const char *params, bool ipv6) { char *args; - args = g_strdup_printf("-machine accel=tcg " - "-netdev user,id=" NETNAME ",tftp=./,bootfile=%s " - "%s ", - disk, params); + args = g_strdup_printf("-machine accel=tcg -nodefaults -boot order=n " + "-netdev user,id=" NETNAME ",tftp=./,bootfile=%s," + "ipv4=%s,ipv6=%s %s", disk, ipv6 ? "off" : "on", + ipv6 ? "on" : "off", params); qtest_start(args); boot_sector_test(); @@ -38,12 +38,17 @@ static void test_pxe_one(const char *params) static void test_pxe_e1000(void) { - test_pxe_one("-device e1000,netdev=" NETNAME); + test_pxe_one("-device e1000,netdev=" NETNAME, false); } static void test_pxe_virtio_pci(void) { - test_pxe_one("-device virtio-net-pci,netdev=" NETNAME); + test_pxe_one("-device virtio-net-pci,netdev=" NETNAME, false); +} + +static void test_pxe_spapr_vlan(void) +{ + test_pxe_one("-device spapr-vlan,netdev=" NETNAME, true); } int main(int argc, char *argv[]) @@ -60,6 +65,9 @@ int main(int argc, char *argv[]) if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { qtest_add_func("pxe/e1000", test_pxe_e1000); qtest_add_func("pxe/virtio", test_pxe_virtio_pci); + } else if (strcmp(arch, "ppc64") == 0) { + qtest_add_func("pxe/virtio", test_pxe_virtio_pci); + qtest_add_func("pxe/spapr-vlan", test_pxe_spapr_vlan); } ret = g_test_run(); boot_sector_cleanup(disk); diff --git a/tests/q35-test.c b/tests/q35-test.c index 71538fc17c..763fe3d6ae 100644 --- a/tests/q35-test.c +++ b/tests/q35-test.c @@ -42,7 +42,7 @@ static void test_smram_lock(void) QPCIDevice *pcidev; QDict *response; - pcibus = qpci_init_pc(); + pcibus = qpci_init_pc(NULL); g_assert(pcibus != NULL); pcidev = qpci_device_find(pcibus, 0); diff --git a/tests/rtas-test.c b/tests/rtas-test.c index 73c780339b..ba0867afbd 100644 --- a/tests/rtas-test.c +++ b/tests/rtas-test.c @@ -22,7 +22,7 @@ static void test_rtas_get_time_of_day(void) t2 = mktimegm(&tm); g_assert(t2 - t1 < 5); /* 5 sec max to run the test */ - qtest_spapr_shutdown(qs); + qtest_shutdown(qs); } int main(int argc, char *argv[]) diff --git a/tests/rtl8139-test.c b/tests/rtl8139-test.c index 13de7eeafd..c2f601a380 100644 --- a/tests/rtl8139-test.c +++ b/tests/rtl8139-test.c @@ -35,7 +35,7 @@ static QPCIDevice *get_device(void) { QPCIDevice *dev; - pcibus = qpci_init_pc(); + pcibus = qpci_init_pc(NULL); qpci_device_foreach(pcibus, 0x10ec, 0x8139, save_fn, &dev); g_assert(dev != NULL); diff --git a/tests/tco-test.c b/tests/tco-test.c index 0d13aa8d63..0d201b1fcb 100644 --- a/tests/tco-test.c +++ b/tests/tco-test.c @@ -57,7 +57,7 @@ static void test_init(TestData *d) qtest_irq_intercept_in(qs, "ioapic"); g_free(s); - bus = qpci_init_pc(); + bus = qpci_init_pc(NULL); d->dev = qpci_device_find(bus, QPCI_DEVFN(0x1f, 0x00)); g_assert(d->dev != NULL); diff --git a/tests/usb-hcd-ehci-test.c b/tests/usb-hcd-ehci-test.c index eb247ad453..a4ceeaaa43 100644 --- a/tests/usb-hcd-ehci-test.c +++ b/tests/usb-hcd-ehci-test.c @@ -56,7 +56,7 @@ static void pci_init(void) if (pcibus) { return; } - pcibus = qpci_init_pc(); + pcibus = qpci_init_pc(NULL); g_assert(pcibus != NULL); qusb_pci_init_one(pcibus, &uhci1, QPCI_DEVFN(0x1d, 0), 4); diff --git a/tests/usb-hcd-uhci-test.c b/tests/usb-hcd-uhci-test.c index 5cd59ad91f..4b951ce492 100644 --- a/tests/usb-hcd-uhci-test.c +++ b/tests/usb-hcd-uhci-test.c @@ -9,9 +9,13 @@ #include "qemu/osdep.h" #include "libqtest.h" +#include "libqos/libqos.h" #include "libqos/usb.h" +#include "libqos/libqos-pc.h" +#include "libqos/libqos-spapr.h" #include "hw/usb/uhci-regs.h" +static QOSState *qs; static void test_uhci_init(void) { @@ -19,13 +23,10 @@ static void test_uhci_init(void) static void test_port(int port) { - QPCIBus *pcibus; struct qhc uhci; g_assert(port > 0); - pcibus = qpci_init_pc(); - g_assert(pcibus != NULL); - qusb_pci_init_one(pcibus, &uhci, QPCI_DEVFN(0x1d, 0), 4); + qusb_pci_init_one(qs->pcibus, &uhci, QPCI_DEVFN(0x1d, 0), 4); uhci_port_test(&uhci, port - 1, UHCI_PORT_CCS); } @@ -75,6 +76,7 @@ static void test_usb_storage_hotplug(void) int main(int argc, char **argv) { + const char *arch = qtest_get_arch(); int ret; g_test_init(&argc, &argv, NULL); @@ -84,11 +86,17 @@ int main(int argc, char **argv) qtest_add_func("/uhci/pci/hotplug", test_uhci_hotplug); qtest_add_func("/uhci/pci/hotplug/usb-storage", test_usb_storage_hotplug); - qtest_start("-device piix3-usb-uhci,id=uhci,addr=1d.0" - " -drive id=drive0,if=none,file=/dev/null,format=raw" - " -device usb-tablet,bus=uhci.0,port=1"); + if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { + qs = qtest_pc_boot("-device piix3-usb-uhci,id=uhci,addr=1d.0" + " -drive id=drive0,if=none,file=/dev/null,format=raw" + " -device usb-tablet,bus=uhci.0,port=1"); + } else if (strcmp(arch, "ppc64") == 0) { + qs = qtest_spapr_boot("-device piix3-usb-uhci,id=uhci,addr=1d.0" + " -drive id=drive0,if=none,file=/dev/null,format=raw" + " -device usb-tablet,bus=uhci.0,port=1"); + } ret = g_test_run(); - qtest_end(); + qtest_shutdown(qs); return ret; } diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c index a39846e6fd..d7c48c589a 100644 --- a/tests/vhost-user-test.c +++ b/tests/vhost-user-test.c @@ -163,7 +163,7 @@ static void init_virtio_dev(TestServer *s) QVirtioPCIDevice *dev; uint32_t features; - bus = qpci_init_pc(); + bus = qpci_init_pc(NULL); g_assert_nonnull(bus); dev = qvirtio_pci_device_find(bus, VIRTIO_ID_NET); @@ -884,7 +884,7 @@ static void test_multiqueue(void) qtest_start(cmd); g_free(cmd); - bus = qpci_init_pc(); + bus = qpci_init_pc(NULL); dev = virtio_net_pci_init(bus, PCI_SLOT); alloc = pc_alloc_init(); diff --git a/tests/virtio-9p-test.c b/tests/virtio-9p-test.c index b8fb6cd869..e8b21967d8 100644 --- a/tests/virtio-9p-test.c +++ b/tests/virtio-9p-test.c @@ -63,7 +63,7 @@ static QVirtIO9P *qvirtio_9p_pci_init(void) v9p = g_new0(QVirtIO9P, 1); v9p->alloc = pc_alloc_init(); - v9p->bus = qpci_init_pc(); + v9p->bus = qpci_init_pc(NULL); dev = qvirtio_pci_device_find(v9p->bus, VIRTIO_ID_9P); g_assert_nonnull(dev); diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c index 811cf756c8..3c4fecc1f0 100644 --- a/tests/virtio-blk-test.c +++ b/tests/virtio-blk-test.c @@ -75,7 +75,7 @@ static QPCIBus *pci_test_start(void) g_free(tmp_path); g_free(cmdline); - return qpci_init_pc(); + return qpci_init_pc(NULL); } static void arm_test_start(void) diff --git a/tests/virtio-net-test.c b/tests/virtio-net-test.c index 361506faf5..a343a6b048 100644 --- a/tests/virtio-net-test.c +++ b/tests/virtio-net-test.c @@ -62,7 +62,7 @@ static QPCIBus *pci_test_start(int socket) qtest_start(cmdline); g_free(cmdline); - return qpci_init_pc(); + return qpci_init_pc(NULL); } static void driver_init(const QVirtioBus *bus, QVirtioDevice *dev) diff --git a/tests/virtio-scsi-test.c b/tests/virtio-scsi-test.c index f1489e68a0..79088bb249 100644 --- a/tests/virtio-scsi-test.c +++ b/tests/virtio-scsi-test.c @@ -146,7 +146,7 @@ static QVirtIOSCSI *qvirtio_scsi_pci_init(int slot) vs = g_new0(QVirtIOSCSI, 1); vs->alloc = pc_alloc_init(); - vs->bus = qpci_init_pc(); + vs->bus = qpci_init_pc(NULL); dev = qvirtio_pci_device_find(vs->bus, VIRTIO_ID_SCSI); vs->dev = (QVirtioDevice *)dev; |