mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-28 12:32:05 -06:00
ppc patch queue 2016-10-06
Currently accumulated target-ppc and spapr machine related patches. - More POWER9 instruction implementations - Additional test case / enabling of test cases for Power - Assorted fixes -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABCAAGBQJX9emTAAoJEGw4ysog2bOS1ucP/3ussng8wx5f7ZIM/qNPK1mp kkskXTa14th0mAg5xC0aMZw7svxWjWBbGvB4lTtMMIwtm9jrPdUpNMOMY1E9+Qeb +ZZHw+9abJp41EZP/CVs+5Zdh2VRmuVoc+YvX3nOP+XiLLu13v9pJ4Y/3Nw+kMAR XhGsXvmnf3Pz7ett5d3xGyF4nZI4UkhGi0jCj4y3Tq7Klakq8kjH8EGsCb1uhC0T dVOEI5XNQ+O3TWhhV1Ihssd3TxmmvSp+V6KdzDKtU+NxKdjrtu2lPfe6+sgFK1gy zu6gg4l8tlL2EgGKgnG7oB9M/bzz1Up8BujOW8uOAw3Ci6rL5v2vRnu3g8+sIW1Q 3fYh8a7YjhljFyR13fb45/vXLBzv5ozKSVXozglTYPd8SD4RdBhkXvuSE6U3mjAp p9k0zcv/rc+I86ikif617Jp6nA+3UgOotoGphGohMudlFem6srpp8bYIbh8vJk77 1zIs7ADo6VBeM32cpu95ZXeMRC3ZJBPuHqr/62Bhst0tN1xoRRWMzvQMQkh3ou2a 4IHVOe7hECsFwueiHoHQS1ybaiRQGz6bXSATPCCKg+ERHoqLzh26yyDf/qD4O50R 4t27YrzlGpRa2w+PLhXzo5sJLNwHU6ptCXgZyv31dPAl5lBd493IpORYFUaz5Akq v9ONu7cYu5Lu2fRXJk/X =YUU1 -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-2.8-20161006' into staging ppc patch queue 2016-10-06 Currently accumulated target-ppc and spapr machine related patches. - More POWER9 instruction implementations - Additional test case / enabling of test cases for Power - Assorted fixes # gpg: Signature made Thu 06 Oct 2016 07:05:07 BST # gpg: using RSA key 0x6C38CACA20D9B392 # gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>" # gpg: aka "David Gibson (Red Hat) <dgibson@redhat.com>" # gpg: aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>" # gpg: aka "David Gibson (kernel.org) <dwg@kernel.org>" # Primary key fingerprint: 75F4 6586 AE61 A66C C44E 87DC 6C38 CACA 20D9 B392 * remotes/dgibson/tags/ppc-for-2.8-20161006: (29 commits) hw/ppc/spapr: Use POWER8 by default for the pseries-2.8 machine tests/pxe: Use -nodefaults to speed up ppc64/ipv6 pxe test spapr: fix check of cpu alias name in spapr_get_cpu_core_type() tests: enable ohci/uhci/xhci tests on PPC64 libqos: use generic qtest_shutdown() libqos: add PCI management in qtest_vboot()/qtest_shutdown() libqos: add PPC64 PCI support target-ppc: fix vmx instruction type/type2 target-ppc/kvm: Enable transactional memory on POWER8 with KVM-HV, too target-ppc/kvm: Add a wrapper function to check for KVM-PR MAINTAINERS: Add two more ppc related files target-ppc: Implement mtvsrws instruction target-ppc: add vclzlsbb/vctzlsbb instructions target-ppc: add vector compare not equal instructions target-ppc: fix invalid mask - cmpl, bctar target-ppc: add stxvb16x instruction target-ppc: add lxvb16x instruction target-ppc: add stxvh8x instruction target-ppc: add lxvh8x instruction target-ppc: improve stxvw4x implementation ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
e902754e3d
45 changed files with 931 additions and 180 deletions
|
@ -620,6 +620,7 @@ S: Maintained
|
||||||
F: hw/ppc/mac_oldworld.c
|
F: hw/ppc/mac_oldworld.c
|
||||||
F: hw/pci-host/grackle.c
|
F: hw/pci-host/grackle.c
|
||||||
F: hw/misc/macio/
|
F: hw/misc/macio/
|
||||||
|
F: hw/intc/heathrow_pic.c
|
||||||
|
|
||||||
PReP
|
PReP
|
||||||
L: qemu-devel@nongnu.org
|
L: qemu-devel@nongnu.org
|
||||||
|
@ -628,6 +629,7 @@ S: Odd Fixes
|
||||||
F: hw/ppc/prep.c
|
F: hw/ppc/prep.c
|
||||||
F: hw/pci-host/prep.[hc]
|
F: hw/pci-host/prep.[hc]
|
||||||
F: hw/isa/pc87312.[hc]
|
F: hw/isa/pc87312.[hc]
|
||||||
|
F: pc-bios/ppc_rom.bin
|
||||||
|
|
||||||
sPAPR
|
sPAPR
|
||||||
M: David Gibson <david@gibson.dropbear.id.au>
|
M: David Gibson <david@gibson.dropbear.id.au>
|
||||||
|
|
104
hw/ppc/spapr.c
104
hw/ppc/spapr.c
|
@ -546,6 +546,51 @@ static int spapr_populate_memory(sPAPRMachineState *spapr, void *fdt)
|
||||||
return 0;
|
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,
|
static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
|
||||||
sPAPRMachineState *spapr)
|
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)));
|
_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_cell(fdt, offset, "reg", index)));
|
||||||
_FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
|
_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)));
|
page_sizes_prop, page_sizes_prop_size)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do the ibm,pa-features property, adjust it for ci-large-pages */
|
spapr_populate_pa_features(env, fdt, offset);
|
||||||
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)));
|
|
||||||
|
|
||||||
_FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id",
|
_FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id",
|
||||||
cs->cpu_index / vcpus_per_socket)));
|
cs->cpu_index / vcpus_per_socket)));
|
||||||
|
@ -1759,7 +1775,7 @@ static void ppc_spapr_init(MachineState *machine)
|
||||||
|
|
||||||
/* init CPUs */
|
/* init CPUs */
|
||||||
if (machine->cpu_model == NULL) {
|
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);
|
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;
|
mc->cpu_index_to_socket_id = spapr_cpu_index_to_socket_id;
|
||||||
|
|
||||||
smc->dr_lmb_enabled = true;
|
smc->dr_lmb_enabled = true;
|
||||||
|
smc->tcg_default_cpu = "POWER8";
|
||||||
mc->query_hotpluggable_cpus = spapr_query_hotpluggable_cpus;
|
mc->query_hotpluggable_cpus = spapr_query_hotpluggable_cpus;
|
||||||
fwc->get_dev_path = spapr_get_fw_dev_path;
|
fwc->get_dev_path = spapr_get_fw_dev_path;
|
||||||
nc->nmi_monitor_handler = spapr_nmi;
|
nc->nmi_monitor_handler = spapr_nmi;
|
||||||
|
@ -2436,19 +2453,40 @@ static const TypeInfo spapr_machine_info = {
|
||||||
} \
|
} \
|
||||||
type_init(spapr_machine_register_##suffix)
|
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
|
* 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_instance_options(MachineState *machine)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static void spapr_machine_2_7_class_options(MachineClass *mc)
|
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
|
* pseries-2.6
|
||||||
|
|
|
@ -92,20 +92,20 @@ char *spapr_get_cpu_core_type(const char *model)
|
||||||
gchar **model_pieces = g_strsplit(model, ",", 2);
|
gchar **model_pieces = g_strsplit(model, ",", 2);
|
||||||
|
|
||||||
core_type = g_strdup_printf("%s-%s", model_pieces[0], TYPE_SPAPR_CPU_CORE);
|
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 */
|
/* Check whether it exists or whether we have to look up an alias name */
|
||||||
if (!object_class_by_name(core_type)) {
|
if (!object_class_by_name(core_type)) {
|
||||||
const char *realmodel;
|
const char *realmodel;
|
||||||
|
|
||||||
g_free(core_type);
|
g_free(core_type);
|
||||||
realmodel = ppc_cpu_lookup_alias(model);
|
core_type = NULL;
|
||||||
|
realmodel = ppc_cpu_lookup_alias(model_pieces[0]);
|
||||||
if (realmodel) {
|
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;
|
return core_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -658,7 +658,7 @@ static void vscsi_process_login(VSCSIState *s, vscsi_req *req)
|
||||||
struct srp_login_rsp *rsp = &iu->srp.login_rsp;
|
struct srp_login_rsp *rsp = &iu->srp.login_rsp;
|
||||||
uint64_t tag = iu->srp.rsp.tag;
|
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
|
/* TODO handle case that requested size is wrong and
|
||||||
* buffer format is wrong
|
* buffer format is wrong
|
||||||
|
|
|
@ -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_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_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_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_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_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 ..."
|
spapr_vscsi_do_crq(unsigned c0, unsigned c1) "crq: %02x %02x ..."
|
||||||
|
|
|
@ -39,6 +39,7 @@ struct sPAPRMachineClass {
|
||||||
/*< public >*/
|
/*< public >*/
|
||||||
bool dr_lmb_enabled; /* enable dynamic-reconfig/hotplug of LMBs */
|
bool dr_lmb_enabled; /* enable dynamic-reconfig/hotplug of LMBs */
|
||||||
bool use_ohci_by_default; /* use USB-OHCI instead of XHCI */
|
bool use_ohci_by_default; /* use USB-OHCI instead of XHCI */
|
||||||
|
const char *tcg_default_cpu; /* which (TCG) CPU to simulate by default */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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(vcmpequh, void, env, avr, avr, avr)
|
||||||
DEF_HELPER_4(vcmpequw, 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(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(vcmpnezb, void, env, avr, avr, avr)
|
||||||
DEF_HELPER_4(vcmpnezh, void, env, avr, avr, avr)
|
DEF_HELPER_4(vcmpnezh, void, env, avr, avr, avr)
|
||||||
DEF_HELPER_4(vcmpnezw, 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(vcmpequh_dot, void, env, avr, avr, avr)
|
||||||
DEF_HELPER_4(vcmpequw_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(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(vcmpnezb_dot, void, env, avr, avr, avr)
|
||||||
DEF_HELPER_4(vcmpnezh_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)
|
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(vpopcnth, void, avr, avr)
|
||||||
DEF_HELPER_2(vpopcntw, void, avr, avr)
|
DEF_HELPER_2(vpopcntw, void, avr, avr)
|
||||||
DEF_HELPER_2(vpopcntd, 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(vbpermd, void, avr, avr, avr)
|
||||||
DEF_HELPER_3(vbpermq, void, avr, avr, avr)
|
DEF_HELPER_3(vbpermq, void, avr, avr, avr)
|
||||||
DEF_HELPER_2(vgbbd, void, avr, avr)
|
DEF_HELPER_2(vgbbd, void, avr, avr)
|
||||||
|
|
|
@ -735,20 +735,24 @@ VCMP(gtsd, >, s64)
|
||||||
#undef VCMP_DO
|
#undef VCMP_DO
|
||||||
#undef VCMP
|
#undef VCMP
|
||||||
|
|
||||||
#define VCMPNEZ_DO(suffix, element, etype, record) \
|
#define VCMPNE_DO(suffix, element, etype, cmpzero, record) \
|
||||||
void helper_vcmpnez##suffix(CPUPPCState *env, ppc_avr_t *r, \
|
void helper_vcmpne##suffix(CPUPPCState *env, ppc_avr_t *r, \
|
||||||
ppc_avr_t *a, ppc_avr_t *b) \
|
ppc_avr_t *a, ppc_avr_t *b) \
|
||||||
{ \
|
{ \
|
||||||
etype ones = (etype)-1; \
|
etype ones = (etype)-1; \
|
||||||
etype all = ones; \
|
etype all = ones; \
|
||||||
etype none = 0; \
|
etype result, none = 0; \
|
||||||
int i; \
|
int i; \
|
||||||
\
|
\
|
||||||
for (i = 0; i < ARRAY_SIZE(r->element); 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) \
|
|| (b->element[i] == 0) \
|
||||||
|| (a->element[i] != b->element[i]) ? \
|
|| (a->element[i] != b->element[i]) ? \
|
||||||
ones : 0x0); \
|
ones : 0x0); \
|
||||||
|
} else { \
|
||||||
|
result = (a->element[i] != b->element[i]) ? ones : 0x0; \
|
||||||
|
} \
|
||||||
r->element[i] = result; \
|
r->element[i] = result; \
|
||||||
all &= result; \
|
all &= result; \
|
||||||
none |= 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)
|
* suffix - instruction mnemonic suffix (b: byte, h: halfword, w: word)
|
||||||
* element - element type to access from vector
|
* element - element type to access from vector
|
||||||
*/
|
*/
|
||||||
#define VCMPNEZ(suffix, element, etype) \
|
#define VCMPNE(suffix, element, etype, cmpzero) \
|
||||||
VCMPNEZ_DO(suffix, element, etype, 0) \
|
VCMPNE_DO(suffix, element, etype, cmpzero, 0) \
|
||||||
VCMPNEZ_DO(suffix##_dot, element, etype, 1)
|
VCMPNE_DO(suffix##_dot, element, etype, cmpzero, 1)
|
||||||
VCMPNEZ(b, u8, uint8_t)
|
VCMPNE(zb, u8, uint8_t, 1)
|
||||||
VCMPNEZ(h, u16, uint16_t)
|
VCMPNE(zh, u16, uint16_t, 1)
|
||||||
VCMPNEZ(w, u32, uint32_t)
|
VCMPNE(zw, u32, uint32_t, 1)
|
||||||
#undef VCMPNEZ_DO
|
VCMPNE(b, u8, uint8_t, 0)
|
||||||
#undef VCMPNEZ
|
VCMPNE(h, u16, uint16_t, 0)
|
||||||
|
VCMPNE(w, u32, uint32_t, 0)
|
||||||
|
#undef VCMPNE_DO
|
||||||
|
#undef VCMPNE
|
||||||
|
|
||||||
#define VCMPFP_DO(suffix, compare, order, record) \
|
#define VCMPFP_DO(suffix, compare, order, record) \
|
||||||
void helper_vcmp##suffix(CPUPPCState *env, ppc_avr_t *r, \
|
void helper_vcmp##suffix(CPUPPCState *env, ppc_avr_t *r, \
|
||||||
|
@ -874,6 +881,36 @@ VCT(uxs, cvtsduw, u32)
|
||||||
VCT(sxs, cvtsdsw, s32)
|
VCT(sxs, cvtsdsw, s32)
|
||||||
#undef VCT
|
#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,
|
void helper_vmhaddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
|
||||||
ppc_avr_t *b, ppc_avr_t *c)
|
ppc_avr_t *b, ppc_avr_t *c)
|
||||||
{
|
{
|
||||||
|
|
|
@ -80,6 +80,7 @@ static int cap_ppc_watchdog;
|
||||||
static int cap_papr;
|
static int cap_papr;
|
||||||
static int cap_htab_fd;
|
static int cap_htab_fd;
|
||||||
static int cap_fixup_hcalls;
|
static int cap_fixup_hcalls;
|
||||||
|
static int cap_htm; /* Hardware transactional memory support */
|
||||||
|
|
||||||
static uint32_t debug_inst_opcode;
|
static uint32_t debug_inst_opcode;
|
||||||
|
|
||||||
|
@ -101,6 +102,16 @@ static void kvm_kick_cpu(void *opaque)
|
||||||
qemu_cpu_kick(CPU(cpu));
|
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);
|
static int kvm_ppc_register_host_cpu_type(void);
|
||||||
|
|
||||||
int kvm_arch_init(MachineState *ms, KVMState *s)
|
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() */
|
* only activated after this by kvmppc_set_papr() */
|
||||||
cap_htab_fd = kvm_check_extension(s, KVM_CAP_PPC_HTAB_FD);
|
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_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) {
|
if (!cap_interrupt_level) {
|
||||||
fprintf(stderr, "KVM: Couldn't find level irq capability. Expect the "
|
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:
|
* For that to work we make a few assumptions:
|
||||||
*
|
*
|
||||||
* - If KVM_CAP_PPC_GET_PVINFO is supported we are running "PR"
|
* - Check whether we are running "PR" KVM which only supports 4K
|
||||||
* KVM which only supports 4K and 16M pages, but supports them
|
* and 16M pages, but supports them regardless of the backing
|
||||||
* regardless of the backing store characteritics. We also don't
|
* store characteritics. We also don't support 1T segments.
|
||||||
* support 1T segments.
|
|
||||||
*
|
*
|
||||||
* This is safe as if HV KVM ever supports that capability or PR
|
* This is safe as if HV KVM ever supports that capability or PR
|
||||||
* KVM grows supports for more page/segment sizes, those versions
|
* 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
|
* implements KVM_CAP_PPC_GET_SMMU_INFO and thus doesn't hit
|
||||||
* this fallback.
|
* this fallback.
|
||||||
*/
|
*/
|
||||||
if (kvm_check_extension(cs->kvm_state, KVM_CAP_PPC_GET_PVINFO)) {
|
if (kvmppc_is_pr(cs->kvm_state)) {
|
||||||
/* No flags */
|
/* No flags */
|
||||||
info->flags = 0;
|
info->flags = 0;
|
||||||
info->slb_size = 64;
|
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);
|
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) {
|
switch (cenv->mmu_model) {
|
||||||
case POWERPC_MMU_BOOKE206:
|
case POWERPC_MMU_BOOKE206:
|
||||||
|
/* This target supports access to KVM's guest TLB */
|
||||||
ret = kvm_booke206_tlb_init(cpu);
|
ret = kvm_booke206_tlb_init(cpu);
|
||||||
break;
|
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:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2268,11 +2286,8 @@ int kvmppc_reset_htab(int shift_hint)
|
||||||
|
|
||||||
/* We have a kernel that predates the htab reset calls. For PR
|
/* 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
|
* KVM, we need to allocate the htab ourselves, for an HV KVM of
|
||||||
* this era, it has allocated a 16MB fixed size hash table
|
* this era, it has allocated a 16MB fixed size hash table already. */
|
||||||
* already. Kernels of this era have the GET_PVINFO capability
|
if (kvmppc_is_pr(kvm_state)) {
|
||||||
* only on PR, so we use this hack to determine the right
|
|
||||||
* answer */
|
|
||||||
if (kvm_check_extension(kvm_state, KVM_CAP_PPC_GET_PVINFO)) {
|
|
||||||
/* PR - tell caller to allocate htab */
|
/* PR - tell caller to allocate htab */
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -2353,6 +2368,11 @@ bool kvmppc_has_cap_fixup_hcalls(void)
|
||||||
return cap_fixup_hcalls;
|
return cap_fixup_hcalls;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool kvmppc_has_cap_htm(void)
|
||||||
|
{
|
||||||
|
return cap_htm;
|
||||||
|
}
|
||||||
|
|
||||||
static PowerPCCPUClass *ppc_cpu_get_family_class(PowerPCCPUClass *pcc)
|
static PowerPCCPUClass *ppc_cpu_get_family_class(PowerPCCPUClass *pcc)
|
||||||
{
|
{
|
||||||
ObjectClass *oc = OBJECT_CLASS(pcc);
|
ObjectClass *oc = OBJECT_CLASS(pcc);
|
||||||
|
|
|
@ -55,6 +55,7 @@ void kvmppc_hash64_free_pteg(uint64_t token);
|
||||||
void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong pte_index,
|
void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong pte_index,
|
||||||
target_ulong pte0, target_ulong pte1);
|
target_ulong pte0, target_ulong pte1);
|
||||||
bool kvmppc_has_cap_fixup_hcalls(void);
|
bool kvmppc_has_cap_fixup_hcalls(void);
|
||||||
|
bool kvmppc_has_cap_htm(void);
|
||||||
int kvmppc_enable_hwrng(void);
|
int kvmppc_enable_hwrng(void);
|
||||||
int kvmppc_put_books_sregs(PowerPCCPU *cpu);
|
int kvmppc_put_books_sregs(PowerPCCPU *cpu);
|
||||||
PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void);
|
PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void);
|
||||||
|
@ -249,6 +250,11 @@ static inline bool kvmppc_has_cap_fixup_hcalls(void)
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool kvmppc_has_cap_htm(void)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static inline int kvmppc_enable_hwrng(void)
|
static inline int kvmppc_enable_hwrng(void)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -6203,7 +6203,7 @@ static opcode_t opcodes[] = {
|
||||||
GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE),
|
GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE),
|
||||||
GEN_HANDLER(cmp, 0x1F, 0x00, 0x00, 0x00400000, PPC_INTEGER),
|
GEN_HANDLER(cmp, 0x1F, 0x00, 0x00, 0x00400000, PPC_INTEGER),
|
||||||
GEN_HANDLER(cmpi, 0x0B, 0xFF, 0xFF, 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),
|
GEN_HANDLER(cmpli, 0x0A, 0xFF, 0xFF, 0x00400000, PPC_INTEGER),
|
||||||
#if defined(TARGET_PPC64)
|
#if defined(TARGET_PPC64)
|
||||||
GEN_HANDLER_E(cmpeqb, 0x1F, 0x00, 0x07, 0x00600000, PPC_NONE, PPC2_ISA300),
|
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(bc, 0x10, 0xFF, 0xFF, 0x00000000, PPC_FLOW),
|
||||||
GEN_HANDLER(bcctr, 0x13, 0x10, 0x10, 0x00000000, PPC_FLOW),
|
GEN_HANDLER(bcctr, 0x13, 0x10, 0x10, 0x00000000, PPC_FLOW),
|
||||||
GEN_HANDLER(bclr, 0x13, 0x10, 0x00, 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(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER),
|
||||||
GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW),
|
GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW),
|
||||||
#if defined(TARGET_PPC64)
|
#if defined(TARGET_PPC64)
|
||||||
|
|
|
@ -510,7 +510,16 @@ GEN_VXRFORM(vcmpeqfp, 3, 3)
|
||||||
GEN_VXRFORM(vcmpgefp, 3, 7)
|
GEN_VXRFORM(vcmpgefp, 3, 7)
|
||||||
GEN_VXRFORM(vcmpgtfp, 3, 11)
|
GEN_VXRFORM(vcmpgtfp, 3, 11)
|
||||||
GEN_VXRFORM(vcmpbfp, 3, 15)
|
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, \
|
GEN_VXRFORM_DUAL(vcmpeqfp, PPC_ALTIVEC, PPC_NONE, \
|
||||||
vcmpequd, PPC_NONE, PPC2_ALTIVEC_207)
|
vcmpequd, PPC_NONE, PPC2_ALTIVEC_207)
|
||||||
GEN_VXRFORM_DUAL(vcmpbfp, PPC_ALTIVEC, PPC_NONE, \
|
GEN_VXRFORM_DUAL(vcmpbfp, PPC_ALTIVEC, PPC_NONE, \
|
||||||
|
@ -584,6 +593,18 @@ static void glue(gen_, name)(DisasContext *ctx) \
|
||||||
tcg_temp_free_ptr(rd); \
|
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(vupkhsb, 7, 8);
|
||||||
GEN_VXFORM_NOA(vupkhsh, 7, 9);
|
GEN_VXFORM_NOA(vupkhsh, 7, 9);
|
||||||
GEN_VXFORM_NOA(vupkhsw, 7, 25);
|
GEN_VXFORM_NOA(vupkhsw, 7, 25);
|
||||||
|
@ -691,17 +712,17 @@ GEN_VXFORM_UIMM_ENV(vcfux, 5, 12);
|
||||||
GEN_VXFORM_UIMM_ENV(vcfsx, 5, 13);
|
GEN_VXFORM_UIMM_ENV(vcfsx, 5, 13);
|
||||||
GEN_VXFORM_UIMM_ENV(vctuxs, 5, 14);
|
GEN_VXFORM_UIMM_ENV(vctuxs, 5, 14);
|
||||||
GEN_VXFORM_UIMM_ENV(vctsxs, 5, 15);
|
GEN_VXFORM_UIMM_ENV(vctsxs, 5, 15);
|
||||||
GEN_VXFORM_DUAL(vspltb, PPC_NONE, PPC2_ALTIVEC_207,
|
GEN_VXFORM_DUAL(vspltb, PPC_ALTIVEC, PPC_NONE,
|
||||||
vextractub, PPC_NONE, PPC2_ISA300);
|
vextractub, PPC_NONE, PPC2_ISA300);
|
||||||
GEN_VXFORM_DUAL(vsplth, PPC_NONE, PPC2_ALTIVEC_207,
|
GEN_VXFORM_DUAL(vsplth, PPC_ALTIVEC, PPC_NONE,
|
||||||
vextractuh, PPC_NONE, PPC2_ISA300);
|
vextractuh, PPC_NONE, PPC2_ISA300);
|
||||||
GEN_VXFORM_DUAL(vspltw, PPC_NONE, PPC2_ALTIVEC_207,
|
GEN_VXFORM_DUAL(vspltw, PPC_ALTIVEC, PPC_NONE,
|
||||||
vextractuw, PPC_NONE, PPC2_ISA300);
|
vextractuw, PPC_NONE, PPC2_ISA300);
|
||||||
GEN_VXFORM_DUAL(vspltisb, PPC_NONE, PPC2_ALTIVEC_207,
|
GEN_VXFORM_DUAL(vspltisb, PPC_ALTIVEC, PPC_NONE,
|
||||||
vinsertb, PPC_NONE, PPC2_ISA300);
|
vinsertb, PPC_NONE, PPC2_ISA300);
|
||||||
GEN_VXFORM_DUAL(vspltish, PPC_NONE, PPC2_ALTIVEC_207,
|
GEN_VXFORM_DUAL(vspltish, PPC_ALTIVEC, PPC_NONE,
|
||||||
vinserth, PPC_NONE, PPC2_ISA300);
|
vinserth, PPC_NONE, PPC2_ISA300);
|
||||||
GEN_VXFORM_DUAL(vspltisw, PPC_NONE, PPC2_ALTIVEC_207,
|
GEN_VXFORM_DUAL(vspltisw, PPC_ALTIVEC, PPC_NONE,
|
||||||
vinsertw, PPC_NONE, PPC2_ISA300);
|
vinsertw, PPC_NONE, PPC2_ISA300);
|
||||||
|
|
||||||
static void gen_vsldoi(DisasContext *ctx)
|
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(vctzh, 1, 24, 29)
|
||||||
GEN_VXFORM_NOA_2(vctzw, 1, 24, 30)
|
GEN_VXFORM_NOA_2(vctzw, 1, 24, 30)
|
||||||
GEN_VXFORM_NOA_2(vctzd, 1, 24, 31)
|
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(vpopcntb, 1, 28)
|
||||||
GEN_VXFORM_NOA(vpopcnth, 1, 29)
|
GEN_VXFORM_NOA(vpopcnth, 1, 29)
|
||||||
GEN_VXFORM_NOA(vpopcntw, 1, 30)
|
GEN_VXFORM_NOA(vpopcntw, 1, 30)
|
||||||
|
|
|
@ -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, name, #name, opc2, opc3) \
|
||||||
GEN_VXRFORM1_300(name##_dot, name##_, #name ".", opc2, (opc3 | (0x1 << 4)))
|
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(vcmpnezb, 3, 4)
|
||||||
GEN_VXRFORM_300(vcmpnezh, 3, 5)
|
GEN_VXRFORM_300(vcmpnezh, 3, 5)
|
||||||
GEN_VXRFORM_300(vcmpnezw, 3, 6)
|
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(vcmpgefp, 3, 7)
|
||||||
GEN_VXRFORM_DUAL(vcmpgtfp, vcmpgtud, 3, 11, PPC_ALTIVEC, PPC_NONE)
|
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(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) \
|
#define GEN_VXFORM_DUAL_INV(name0, name1, opc2, opc3, inval0, inval1, type) \
|
||||||
GEN_OPCODE_DUAL(name0##_##name1, 0x04, opc2, opc3, inval0, inval1, type, \
|
GEN_OPCODE_DUAL(name0##_##name1, 0x04, opc2, opc3, inval0, inval1, type, \
|
||||||
PPC_NONE)
|
PPC_NONE)
|
||||||
GEN_VXFORM_DUAL_INV(vspltb, vextractub, 6, 8, 0x00000000, 0x100000,
|
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,
|
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,
|
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_300_EXT(vextractd, 6, 11, 0x100000),
|
||||||
GEN_VXFORM_DUAL_INV(vspltisb, vinsertb, 6, 12, 0x00000000, 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,
|
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,
|
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_EXT(vinsertd, 6, 15, 0x100000),
|
||||||
GEN_VXFORM_300_EO(vctzb, 0x01, 0x18, 0x1C),
|
GEN_VXFORM_300_EO(vctzb, 0x01, 0x18, 0x1C),
|
||||||
GEN_VXFORM_300_EO(vctzh, 0x01, 0x18, 0x1D),
|
GEN_VXFORM_300_EO(vctzh, 0x01, 0x18, 0x1D),
|
||||||
GEN_VXFORM_300_EO(vctzw, 0x01, 0x18, 0x1E),
|
GEN_VXFORM_300_EO(vctzw, 0x01, 0x18, 0x1E),
|
||||||
GEN_VXFORM_300_EO(vctzd, 0x01, 0x18, 0x1F),
|
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),
|
GEN_VXFORM_300(vpermr, 0x1D, 0xFF),
|
||||||
|
|
||||||
#define GEN_VXFORM_NOA(name, opc2, opc3) \
|
#define GEN_VXFORM_NOA(name, opc2, opc3) \
|
||||||
|
|
|
@ -75,7 +75,6 @@ static void gen_lxvdsx(DisasContext *ctx)
|
||||||
static void gen_lxvw4x(DisasContext *ctx)
|
static void gen_lxvw4x(DisasContext *ctx)
|
||||||
{
|
{
|
||||||
TCGv EA;
|
TCGv EA;
|
||||||
TCGv_i64 tmp;
|
|
||||||
TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode));
|
TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode));
|
||||||
TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode));
|
TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode));
|
||||||
if (unlikely(!ctx->vsx_enabled)) {
|
if (unlikely(!ctx->vsx_enabled)) {
|
||||||
|
@ -84,22 +83,95 @@ static void gen_lxvw4x(DisasContext *ctx)
|
||||||
}
|
}
|
||||||
gen_set_access_type(ctx, ACCESS_INT);
|
gen_set_access_type(ctx, ACCESS_INT);
|
||||||
EA = tcg_temp_new();
|
EA = tcg_temp_new();
|
||||||
tmp = tcg_temp_new_i64();
|
|
||||||
|
|
||||||
gen_addr_reg_index(ctx, EA);
|
gen_addr_reg_index(ctx, EA);
|
||||||
gen_qemu_ld32u_i64(ctx, tmp, EA);
|
if (ctx->le_mode) {
|
||||||
tcg_gen_addi_tl(EA, EA, 4);
|
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||||
gen_qemu_ld32u_i64(ctx, xth, EA);
|
TCGv_i64 t1 = tcg_temp_new_i64();
|
||||||
tcg_gen_deposit_i64(xth, xth, tmp, 32, 32);
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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(EA);
|
||||||
tcg_temp_free_i64(tmp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define VSX_STORE_SCALAR(name, operation) \
|
#define VSX_STORE_SCALAR(name, operation) \
|
||||||
|
@ -142,7 +214,8 @@ static void gen_stxvd2x(DisasContext *ctx)
|
||||||
|
|
||||||
static void gen_stxvw4x(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;
|
TCGv EA;
|
||||||
if (unlikely(!ctx->vsx_enabled)) {
|
if (unlikely(!ctx->vsx_enabled)) {
|
||||||
gen_exception(ctx, POWERPC_EXCP_VSXU);
|
gen_exception(ctx, POWERPC_EXCP_VSXU);
|
||||||
|
@ -151,21 +224,75 @@ static void gen_stxvw4x(DisasContext *ctx)
|
||||||
gen_set_access_type(ctx, ACCESS_INT);
|
gen_set_access_type(ctx, ACCESS_INT);
|
||||||
EA = tcg_temp_new();
|
EA = tcg_temp_new();
|
||||||
gen_addr_reg_index(ctx, EA);
|
gen_addr_reg_index(ctx, EA);
|
||||||
tmp = tcg_temp_new_i64();
|
if (ctx->le_mode) {
|
||||||
|
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||||
tcg_gen_shri_i64(tmp, cpu_vsrh(xS(ctx->opcode)), 32);
|
TCGv_i64 t1 = tcg_temp_new_i64();
|
||||||
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);
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gen_stxvh8x(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);
|
||||||
|
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(EA);
|
||||||
tcg_temp_free_i64(tmp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MV_VSRW(name, tcgop1, tcgop2, target, source) \
|
#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(mfvsrd, cpu_gpr[rA(ctx->opcode)], cpu_vsrh(xS(ctx->opcode)))
|
||||||
MV_VSRD(mtvsrd, cpu_vsrh(xT(ctx->opcode)), cpu_gpr[rA(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
|
#endif
|
||||||
|
|
||||||
static void gen_xxpermdi(DisasContext *ctx)
|
static void gen_xxpermdi(DisasContext *ctx)
|
||||||
|
|
|
@ -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(lxvd2x, 0x1F, 0x0C, 0x1A, 0, PPC_NONE, PPC2_VSX),
|
||||||
GEN_HANDLER_E(lxvdsx, 0x1F, 0x0C, 0x0A, 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(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(stxsdx, 0x1F, 0xC, 0x16, 0, PPC_NONE, PPC2_VSX),
|
||||||
GEN_HANDLER_E(stxsibx, 0x1F, 0xD, 0x1C, 0, PPC_NONE, PPC2_ISA300),
|
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(stxsspx, 0x1F, 0xC, 0x14, 0, PPC_NONE, PPC2_VSX207),
|
||||||
GEN_HANDLER_E(stxvd2x, 0x1F, 0xC, 0x1E, 0, PPC_NONE, PPC2_VSX),
|
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(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(mfvsrwz, 0x1F, 0x13, 0x03, 0x0000F800, PPC_NONE, PPC2_VSX207),
|
||||||
GEN_HANDLER_E(mtvsrwa, 0x1F, 0x13, 0x06, 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)
|
#if defined(TARGET_PPC64)
|
||||||
GEN_HANDLER_E(mfvsrd, 0x1F, 0x13, 0x01, 0x0000F800, PPC_NONE, PPC2_VSX207),
|
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(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
|
#endif
|
||||||
|
|
||||||
#define GEN_XX1FORM(name, opc2, opc3, fl2) \
|
#define GEN_XX1FORM(name, opc2, opc3, fl2) \
|
||||||
|
|
|
@ -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/postcopy-test$(EXESUF)
|
||||||
check-qtest-ppc64-y += tests/boot-serial-test$(EXESUF)
|
check-qtest-ppc64-y += tests/boot-serial-test$(EXESUF)
|
||||||
check-qtest-ppc64-y += tests/rtas-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)
|
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 = $(libqos-obj-y) tests/libqos/malloc-spapr.o
|
||||||
libqos-spapr-obj-y += tests/libqos/libqos-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/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 = $(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/malloc-pc.o tests/libqos/libqos-pc.o
|
||||||
libqos-pc-obj-y += tests/libqos/ahci.o
|
libqos-pc-obj-y += tests/libqos/ahci.o
|
||||||
libqos-omap-obj-y = $(libqos-obj-y) tests/libqos/i2c-omap.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-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
|
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
|
tests/device-introspect-test$(EXESUF): tests/device-introspect-test.o
|
||||||
|
|
|
@ -77,6 +77,15 @@ int boot_sector_init(const char *fname)
|
||||||
fprintf(stderr, "Couldn't open \"%s\": %s", fname, strerror(errno));
|
fprintf(stderr, "Couldn't open \"%s\": %s", fname, strerror(errno));
|
||||||
return 1;
|
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);
|
fwrite(boot_sector, 1, sizeof boot_sector, f);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -390,7 +390,7 @@ static void data_test_init(e1000e_device *d)
|
||||||
qtest_start(cmdline);
|
qtest_start(cmdline);
|
||||||
g_free(cmdline);
|
g_free(cmdline);
|
||||||
|
|
||||||
test_bus = qpci_init_pc();
|
test_bus = qpci_init_pc(NULL);
|
||||||
g_assert_nonnull(test_bus);
|
g_assert_nonnull(test_bus);
|
||||||
|
|
||||||
test_alloc = pc_alloc_init();
|
test_alloc = pc_alloc_init();
|
||||||
|
|
|
@ -38,7 +38,7 @@ static QPCIBus *test_start_get_bus(const TestData *s)
|
||||||
cmdline = g_strdup_printf("-smp %d", s->num_cpus);
|
cmdline = g_strdup_printf("-smp %d", s->num_cpus);
|
||||||
qtest_start(cmdline);
|
qtest_start(cmdline);
|
||||||
g_free(cmdline);
|
g_free(cmdline);
|
||||||
return qpci_init_pc();
|
return qpci_init_pc(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_i440fx_defaults(gconstpointer opaque)
|
static void test_i440fx_defaults(gconstpointer opaque)
|
||||||
|
|
|
@ -143,7 +143,7 @@ static QPCIDevice *get_pci_device(uint16_t *bmdma_base)
|
||||||
uint16_t vendor_id, device_id;
|
uint16_t vendor_id, device_id;
|
||||||
|
|
||||||
if (!pcibus) {
|
if (!pcibus) {
|
||||||
pcibus = qpci_init_pc();
|
pcibus = qpci_init_pc(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find PCI device and verify it's the right one */
|
/* Find PCI device and verify it's the right one */
|
||||||
|
|
|
@ -105,7 +105,7 @@ static void setup_vm_cmd(IVState *s, const char *cmd, bool msix)
|
||||||
uint64_t barsize;
|
uint64_t barsize;
|
||||||
|
|
||||||
s->qtest = qtest_start(cmd);
|
s->qtest = qtest_start(cmd);
|
||||||
s->pcibus = qpci_init_pc();
|
s->pcibus = qpci_init_pc(NULL);
|
||||||
s->dev = get_device(s->pcibus);
|
s->dev = get_device(s->pcibus);
|
||||||
|
|
||||||
s->reg_base = qpci_iomap(s->dev, 0, &barsize);
|
s->reg_base = qpci_iomap(s->dev, 0, &barsize);
|
||||||
|
|
|
@ -128,7 +128,7 @@ QPCIDevice *get_ahci_device(uint32_t *fingerprint)
|
||||||
uint32_t ahci_fingerprint;
|
uint32_t ahci_fingerprint;
|
||||||
QPCIBus *pcibus;
|
QPCIBus *pcibus;
|
||||||
|
|
||||||
pcibus = qpci_init_pc();
|
pcibus = qpci_init_pc(NULL);
|
||||||
|
|
||||||
/* Find the AHCI PCI device and verify it's the right one. */
|
/* Find the AHCI PCI device and verify it's the right one. */
|
||||||
ahci = qpci_device_find(pcibus, QPCI_DEVFN(0x1F, 0x02));
|
ahci = qpci_device_find(pcibus, QPCI_DEVFN(0x1F, 0x02));
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "libqos/libqos-pc.h"
|
#include "libqos/libqos-pc.h"
|
||||||
#include "libqos/malloc-pc.h"
|
#include "libqos/malloc-pc.h"
|
||||||
|
#include "libqos/pci-pc.h"
|
||||||
|
|
||||||
static QOSOps qos_ops = {
|
static QOSOps qos_ops = {
|
||||||
.init_allocator = pc_alloc_init_flags,
|
.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)
|
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)
|
void qtest_pc_shutdown(QOSState *qs)
|
||||||
{
|
{
|
||||||
return qtest_shutdown(qs);
|
return qtest_common_shutdown(qs);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "libqos/libqos-spapr.h"
|
#include "libqos/libqos-spapr.h"
|
||||||
#include "libqos/malloc-spapr.h"
|
#include "libqos/malloc-spapr.h"
|
||||||
|
#include "libqos/pci-spapr.h"
|
||||||
|
|
||||||
static QOSOps qos_ops = {
|
static QOSOps qos_ops = {
|
||||||
.init_allocator = spapr_alloc_init_flags,
|
.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)
|
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)
|
void qtest_spapr_shutdown(QOSState *qs)
|
||||||
{
|
{
|
||||||
return qtest_shutdown(qs);
|
return qtest_common_shutdown(qs);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,14 @@ QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap)
|
||||||
cmdline = g_strdup_vprintf(cmdline_fmt, ap);
|
cmdline = g_strdup_vprintf(cmdline_fmt, ap);
|
||||||
qs->qts = qtest_start(cmdline);
|
qs->qts = qtest_start(cmdline);
|
||||||
qs->ops = ops;
|
qs->ops = ops;
|
||||||
if (ops && ops->init_allocator) {
|
if (ops) {
|
||||||
|
if (ops->init_allocator) {
|
||||||
qs->alloc = ops->init_allocator(ALLOC_NO_FLAGS);
|
qs->alloc = ops->init_allocator(ALLOC_NO_FLAGS);
|
||||||
}
|
}
|
||||||
|
if (ops->qpci_init && qs->alloc) {
|
||||||
|
qs->pcibus = ops->qpci_init(qs->alloc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
g_free(cmdline);
|
g_free(cmdline);
|
||||||
return qs;
|
return qs;
|
||||||
|
@ -47,16 +52,31 @@ QOSState *qtest_boot(QOSOps *ops, const char *cmdline_fmt, ...)
|
||||||
/**
|
/**
|
||||||
* Tear down the QEMU instance.
|
* 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) {
|
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->ops->uninit_allocator(qs->alloc);
|
||||||
qs->alloc = NULL;
|
qs->alloc = NULL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
qtest_quit(qs->qts);
|
qtest_quit(qs->qts);
|
||||||
g_free(qs);
|
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)
|
void set_context(QOSState *s)
|
||||||
{
|
{
|
||||||
global_qtest = s->qts;
|
global_qtest = s->qts;
|
||||||
|
|
|
@ -5,19 +5,26 @@
|
||||||
#include "libqos/pci.h"
|
#include "libqos/pci.h"
|
||||||
#include "libqos/malloc-pc.h"
|
#include "libqos/malloc-pc.h"
|
||||||
|
|
||||||
|
typedef struct QOSState QOSState;
|
||||||
|
|
||||||
typedef struct QOSOps {
|
typedef struct QOSOps {
|
||||||
QGuestAllocator *(*init_allocator)(QAllocOpts);
|
QGuestAllocator *(*init_allocator)(QAllocOpts);
|
||||||
void (*uninit_allocator)(QGuestAllocator *);
|
void (*uninit_allocator)(QGuestAllocator *);
|
||||||
|
QPCIBus *(*qpci_init)(QGuestAllocator *alloc);
|
||||||
|
void (*qpci_free)(QPCIBus *bus);
|
||||||
|
void (*shutdown)(QOSState *);
|
||||||
} QOSOps;
|
} QOSOps;
|
||||||
|
|
||||||
typedef struct QOSState {
|
struct QOSState {
|
||||||
QTestState *qts;
|
QTestState *qts;
|
||||||
QGuestAllocator *alloc;
|
QGuestAllocator *alloc;
|
||||||
|
QPCIBus *pcibus;
|
||||||
QOSOps *ops;
|
QOSOps *ops;
|
||||||
} QOSState;
|
};
|
||||||
|
|
||||||
QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap);
|
QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap);
|
||||||
QOSState *qtest_boot(QOSOps *ops, const char *cmdline_fmt, ...);
|
QOSState *qtest_boot(QOSOps *ops, const char *cmdline_fmt, ...);
|
||||||
|
void qtest_common_shutdown(QOSState *qs);
|
||||||
void qtest_shutdown(QOSState *qs);
|
void qtest_shutdown(QOSState *qs);
|
||||||
bool have_qemu_img(void);
|
bool have_qemu_img(void);
|
||||||
void mkimg(const char *file, const char *fmt, unsigned size_mb);
|
void mkimg(const char *file, const char *fmt, unsigned size_mb);
|
||||||
|
|
|
@ -212,7 +212,7 @@ static void qpci_pc_iounmap(QPCIBus *bus, void *data)
|
||||||
/* FIXME */
|
/* FIXME */
|
||||||
}
|
}
|
||||||
|
|
||||||
QPCIBus *qpci_init_pc(void)
|
QPCIBus *qpci_init_pc(QGuestAllocator *alloc)
|
||||||
{
|
{
|
||||||
QPCIBusPC *ret;
|
QPCIBusPC *ret;
|
||||||
|
|
||||||
|
@ -255,28 +255,6 @@ void qpci_free_pc(QPCIBus *bus)
|
||||||
g_free(s);
|
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)
|
void qpci_unplug_acpi_device_test(const char *id, uint8_t slot)
|
||||||
{
|
{
|
||||||
QDict *response;
|
QDict *response;
|
||||||
|
|
|
@ -14,8 +14,9 @@
|
||||||
#define LIBQOS_PCI_PC_H
|
#define LIBQOS_PCI_PC_H
|
||||||
|
|
||||||
#include "libqos/pci.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);
|
void qpci_free_pc(QPCIBus *bus);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
288
tests/libqos/pci-spapr.c
Normal file
288
tests/libqos/pci-spapr.c
Normal file
|
@ -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);
|
||||||
|
}
|
17
tests/libqos/pci-spapr.h
Normal file
17
tests/libqos/pci-spapr.h
Normal file
|
@ -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
|
|
@ -263,4 +263,24 @@ void qpci_iounmap(QPCIDevice *dev, void *data)
|
||||||
dev->bus->iounmap(dev->bus, 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);
|
||||||
|
}
|
||||||
|
|
|
@ -69,3 +69,48 @@ int qrtas_get_time_of_day(QGuestAllocator *alloc, struct tm *tm, uint32_t *ns)
|
||||||
|
|
||||||
return res;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -8,4 +8,8 @@
|
||||||
#include "libqos/malloc.h"
|
#include "libqos/malloc.h"
|
||||||
|
|
||||||
int qrtas_get_time_of_day(QGuestAllocator *alloc, struct tm *tm, uint32_t *ns);
|
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 */
|
#endif /* LIBQOS_RTAS_H */
|
||||||
|
|
|
@ -21,14 +21,14 @@
|
||||||
|
|
||||||
static const char *disk = "tests/pxe-test-disk.raw";
|
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;
|
char *args;
|
||||||
|
|
||||||
args = g_strdup_printf("-machine accel=tcg "
|
args = g_strdup_printf("-machine accel=tcg -nodefaults -boot order=n "
|
||||||
"-netdev user,id=" NETNAME ",tftp=./,bootfile=%s "
|
"-netdev user,id=" NETNAME ",tftp=./,bootfile=%s,"
|
||||||
"%s ",
|
"ipv4=%s,ipv6=%s %s", disk, ipv6 ? "off" : "on",
|
||||||
disk, params);
|
ipv6 ? "on" : "off", params);
|
||||||
|
|
||||||
qtest_start(args);
|
qtest_start(args);
|
||||||
boot_sector_test();
|
boot_sector_test();
|
||||||
|
@ -38,12 +38,17 @@ static void test_pxe_one(const char *params)
|
||||||
|
|
||||||
static void test_pxe_e1000(void)
|
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)
|
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[])
|
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) {
|
if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
|
||||||
qtest_add_func("pxe/e1000", test_pxe_e1000);
|
qtest_add_func("pxe/e1000", test_pxe_e1000);
|
||||||
qtest_add_func("pxe/virtio", test_pxe_virtio_pci);
|
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();
|
ret = g_test_run();
|
||||||
boot_sector_cleanup(disk);
|
boot_sector_cleanup(disk);
|
||||||
|
|
|
@ -42,7 +42,7 @@ static void test_smram_lock(void)
|
||||||
QPCIDevice *pcidev;
|
QPCIDevice *pcidev;
|
||||||
QDict *response;
|
QDict *response;
|
||||||
|
|
||||||
pcibus = qpci_init_pc();
|
pcibus = qpci_init_pc(NULL);
|
||||||
g_assert(pcibus != NULL);
|
g_assert(pcibus != NULL);
|
||||||
|
|
||||||
pcidev = qpci_device_find(pcibus, 0);
|
pcidev = qpci_device_find(pcibus, 0);
|
||||||
|
|
|
@ -22,7 +22,7 @@ static void test_rtas_get_time_of_day(void)
|
||||||
t2 = mktimegm(&tm);
|
t2 = mktimegm(&tm);
|
||||||
g_assert(t2 - t1 < 5); /* 5 sec max to run the test */
|
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[])
|
int main(int argc, char *argv[])
|
||||||
|
|
|
@ -35,7 +35,7 @@ static QPCIDevice *get_device(void)
|
||||||
{
|
{
|
||||||
QPCIDevice *dev;
|
QPCIDevice *dev;
|
||||||
|
|
||||||
pcibus = qpci_init_pc();
|
pcibus = qpci_init_pc(NULL);
|
||||||
qpci_device_foreach(pcibus, 0x10ec, 0x8139, save_fn, &dev);
|
qpci_device_foreach(pcibus, 0x10ec, 0x8139, save_fn, &dev);
|
||||||
g_assert(dev != NULL);
|
g_assert(dev != NULL);
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ static void test_init(TestData *d)
|
||||||
qtest_irq_intercept_in(qs, "ioapic");
|
qtest_irq_intercept_in(qs, "ioapic");
|
||||||
g_free(s);
|
g_free(s);
|
||||||
|
|
||||||
bus = qpci_init_pc();
|
bus = qpci_init_pc(NULL);
|
||||||
d->dev = qpci_device_find(bus, QPCI_DEVFN(0x1f, 0x00));
|
d->dev = qpci_device_find(bus, QPCI_DEVFN(0x1f, 0x00));
|
||||||
g_assert(d->dev != NULL);
|
g_assert(d->dev != NULL);
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ static void pci_init(void)
|
||||||
if (pcibus) {
|
if (pcibus) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pcibus = qpci_init_pc();
|
pcibus = qpci_init_pc(NULL);
|
||||||
g_assert(pcibus != NULL);
|
g_assert(pcibus != NULL);
|
||||||
|
|
||||||
qusb_pci_init_one(pcibus, &uhci1, QPCI_DEVFN(0x1d, 0), 4);
|
qusb_pci_init_one(pcibus, &uhci1, QPCI_DEVFN(0x1d, 0), 4);
|
||||||
|
|
|
@ -9,9 +9,13 @@
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "libqtest.h"
|
#include "libqtest.h"
|
||||||
|
#include "libqos/libqos.h"
|
||||||
#include "libqos/usb.h"
|
#include "libqos/usb.h"
|
||||||
|
#include "libqos/libqos-pc.h"
|
||||||
|
#include "libqos/libqos-spapr.h"
|
||||||
#include "hw/usb/uhci-regs.h"
|
#include "hw/usb/uhci-regs.h"
|
||||||
|
|
||||||
|
static QOSState *qs;
|
||||||
|
|
||||||
static void test_uhci_init(void)
|
static void test_uhci_init(void)
|
||||||
{
|
{
|
||||||
|
@ -19,13 +23,10 @@ static void test_uhci_init(void)
|
||||||
|
|
||||||
static void test_port(int port)
|
static void test_port(int port)
|
||||||
{
|
{
|
||||||
QPCIBus *pcibus;
|
|
||||||
struct qhc uhci;
|
struct qhc uhci;
|
||||||
|
|
||||||
g_assert(port > 0);
|
g_assert(port > 0);
|
||||||
pcibus = qpci_init_pc();
|
qusb_pci_init_one(qs->pcibus, &uhci, QPCI_DEVFN(0x1d, 0), 4);
|
||||||
g_assert(pcibus != NULL);
|
|
||||||
qusb_pci_init_one(pcibus, &uhci, QPCI_DEVFN(0x1d, 0), 4);
|
|
||||||
uhci_port_test(&uhci, port - 1, UHCI_PORT_CCS);
|
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)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
const char *arch = qtest_get_arch();
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
g_test_init(&argc, &argv, NULL);
|
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", test_uhci_hotplug);
|
||||||
qtest_add_func("/uhci/pci/hotplug/usb-storage", test_usb_storage_hotplug);
|
qtest_add_func("/uhci/pci/hotplug/usb-storage", test_usb_storage_hotplug);
|
||||||
|
|
||||||
qtest_start("-device piix3-usb-uhci,id=uhci,addr=1d.0"
|
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"
|
" -drive id=drive0,if=none,file=/dev/null,format=raw"
|
||||||
" -device usb-tablet,bus=uhci.0,port=1");
|
" -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();
|
ret = g_test_run();
|
||||||
qtest_end();
|
qtest_shutdown(qs);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -163,7 +163,7 @@ static void init_virtio_dev(TestServer *s)
|
||||||
QVirtioPCIDevice *dev;
|
QVirtioPCIDevice *dev;
|
||||||
uint32_t features;
|
uint32_t features;
|
||||||
|
|
||||||
bus = qpci_init_pc();
|
bus = qpci_init_pc(NULL);
|
||||||
g_assert_nonnull(bus);
|
g_assert_nonnull(bus);
|
||||||
|
|
||||||
dev = qvirtio_pci_device_find(bus, VIRTIO_ID_NET);
|
dev = qvirtio_pci_device_find(bus, VIRTIO_ID_NET);
|
||||||
|
@ -884,7 +884,7 @@ static void test_multiqueue(void)
|
||||||
qtest_start(cmd);
|
qtest_start(cmd);
|
||||||
g_free(cmd);
|
g_free(cmd);
|
||||||
|
|
||||||
bus = qpci_init_pc();
|
bus = qpci_init_pc(NULL);
|
||||||
dev = virtio_net_pci_init(bus, PCI_SLOT);
|
dev = virtio_net_pci_init(bus, PCI_SLOT);
|
||||||
|
|
||||||
alloc = pc_alloc_init();
|
alloc = pc_alloc_init();
|
||||||
|
|
|
@ -63,7 +63,7 @@ static QVirtIO9P *qvirtio_9p_pci_init(void)
|
||||||
|
|
||||||
v9p = g_new0(QVirtIO9P, 1);
|
v9p = g_new0(QVirtIO9P, 1);
|
||||||
v9p->alloc = pc_alloc_init();
|
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);
|
dev = qvirtio_pci_device_find(v9p->bus, VIRTIO_ID_9P);
|
||||||
g_assert_nonnull(dev);
|
g_assert_nonnull(dev);
|
||||||
|
|
|
@ -75,7 +75,7 @@ static QPCIBus *pci_test_start(void)
|
||||||
g_free(tmp_path);
|
g_free(tmp_path);
|
||||||
g_free(cmdline);
|
g_free(cmdline);
|
||||||
|
|
||||||
return qpci_init_pc();
|
return qpci_init_pc(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void arm_test_start(void)
|
static void arm_test_start(void)
|
||||||
|
|
|
@ -62,7 +62,7 @@ static QPCIBus *pci_test_start(int socket)
|
||||||
qtest_start(cmdline);
|
qtest_start(cmdline);
|
||||||
g_free(cmdline);
|
g_free(cmdline);
|
||||||
|
|
||||||
return qpci_init_pc();
|
return qpci_init_pc(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void driver_init(const QVirtioBus *bus, QVirtioDevice *dev)
|
static void driver_init(const QVirtioBus *bus, QVirtioDevice *dev)
|
||||||
|
|
|
@ -146,7 +146,7 @@ static QVirtIOSCSI *qvirtio_scsi_pci_init(int slot)
|
||||||
|
|
||||||
vs = g_new0(QVirtIOSCSI, 1);
|
vs = g_new0(QVirtIOSCSI, 1);
|
||||||
vs->alloc = pc_alloc_init();
|
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);
|
dev = qvirtio_pci_device_find(vs->bus, VIRTIO_ID_SCSI);
|
||||||
vs->dev = (QVirtioDevice *)dev;
|
vs->dev = (QVirtioDevice *)dev;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue