From 6875dc8ea4f9e14f33c217c3596af51c60cfd1b5 Mon Sep 17 00:00:00 2001 From: Liu Yu-B13201 Date: Thu, 29 Sep 2011 17:52:49 +0000 Subject: [PATCH 01/25] ppc/e500_pci: Fix code style MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Put trailing statements on next line. Signed-off-by: Liu Yu Reviewed-by: Andreas Färber Signed-off-by: Alexander Graf --- hw/ppce500_pci.c | 76 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 56 insertions(+), 20 deletions(-) diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c index 2db365d0b6..0ece422446 100644 --- a/hw/ppce500_pci.c +++ b/hw/ppce500_pci.c @@ -98,11 +98,20 @@ static uint32_t pci_reg_read4(void *opaque, target_phys_addr_t addr) case PPCE500_PCI_OW3: case PPCE500_PCI_OW4: switch (addr & 0xC) { - case PCI_POTAR: value = pci->pob[(addr >> 5) & 0x7].potar; break; - case PCI_POTEAR: value = pci->pob[(addr >> 5) & 0x7].potear; break; - case PCI_POWBAR: value = pci->pob[(addr >> 5) & 0x7].powbar; break; - case PCI_POWAR: value = pci->pob[(addr >> 5) & 0x7].powar; break; - default: break; + case PCI_POTAR: + value = pci->pob[(addr >> 5) & 0x7].potar; + break; + case PCI_POTEAR: + value = pci->pob[(addr >> 5) & 0x7].potear; + break; + case PCI_POWBAR: + value = pci->pob[(addr >> 5) & 0x7].powbar; + break; + case PCI_POWAR: + value = pci->pob[(addr >> 5) & 0x7].powar; + break; + default: + break; } break; @@ -110,11 +119,20 @@ static uint32_t pci_reg_read4(void *opaque, target_phys_addr_t addr) case PPCE500_PCI_IW2: case PPCE500_PCI_IW1: switch (addr & 0xC) { - case PCI_PITAR: value = pci->pib[(addr >> 5) & 0x3].pitar; break; - case PCI_PIWBAR: value = pci->pib[(addr >> 5) & 0x3].piwbar; break; - case PCI_PIWBEAR: value = pci->pib[(addr >> 5) & 0x3].piwbear; break; - case PCI_PIWAR: value = pci->pib[(addr >> 5) & 0x3].piwar; break; - default: break; + case PCI_PITAR: + value = pci->pib[(addr >> 5) & 0x3].pitar; + break; + case PCI_PIWBAR: + value = pci->pib[(addr >> 5) & 0x3].piwbar; + break; + case PCI_PIWBEAR: + value = pci->pib[(addr >> 5) & 0x3].piwbear; + break; + case PCI_PIWAR: + value = pci->pib[(addr >> 5) & 0x3].piwar; + break; + default: + break; }; break; @@ -154,11 +172,20 @@ static void pci_reg_write4(void *opaque, target_phys_addr_t addr, case PPCE500_PCI_OW3: case PPCE500_PCI_OW4: switch (addr & 0xC) { - case PCI_POTAR: pci->pob[(addr >> 5) & 0x7].potar = value; break; - case PCI_POTEAR: pci->pob[(addr >> 5) & 0x7].potear = value; break; - case PCI_POWBAR: pci->pob[(addr >> 5) & 0x7].powbar = value; break; - case PCI_POWAR: pci->pob[(addr >> 5) & 0x7].powar = value; break; - default: break; + case PCI_POTAR: + pci->pob[(addr >> 5) & 0x7].potar = value; + break; + case PCI_POTEAR: + pci->pob[(addr >> 5) & 0x7].potear = value; + break; + case PCI_POWBAR: + pci->pob[(addr >> 5) & 0x7].powbar = value; + break; + case PCI_POWAR: + pci->pob[(addr >> 5) & 0x7].powar = value; + break; + default: + break; }; break; @@ -166,11 +193,20 @@ static void pci_reg_write4(void *opaque, target_phys_addr_t addr, case PPCE500_PCI_IW2: case PPCE500_PCI_IW1: switch (addr & 0xC) { - case PCI_PITAR: pci->pib[(addr >> 5) & 0x3].pitar = value; break; - case PCI_PIWBAR: pci->pib[(addr >> 5) & 0x3].piwbar = value; break; - case PCI_PIWBEAR: pci->pib[(addr >> 5) & 0x3].piwbear = value; break; - case PCI_PIWAR: pci->pib[(addr >> 5) & 0x3].piwar = value; break; - default: break; + case PCI_PITAR: + pci->pib[(addr >> 5) & 0x3].pitar = value; + break; + case PCI_PIWBAR: + pci->pib[(addr >> 5) & 0x3].piwbar = value; + break; + case PCI_PIWBEAR: + pci->pib[(addr >> 5) & 0x3].piwbear = value; + break; + case PCI_PIWAR: + pci->pib[(addr >> 5) & 0x3].piwar = value; + break; + default: + break; }; break; From eeae2e7b52255dae0976a027b6e11274990c708d Mon Sep 17 00:00:00 2001 From: Liu Yu-B13201 Date: Thu, 29 Sep 2011 17:52:50 +0000 Subject: [PATCH 02/25] ppc/e500_pci: Fix an array overflow issue When access PPCE500_PCI_IW1 the previous index get overflow. The patch fix the issue and update all to keep consistent style. Signed-off-by: Liu Yu Signed-off-by: Alexander Graf --- hw/ppce500_pci.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c index 0ece422446..960a5d0c60 100644 --- a/hw/ppce500_pci.c +++ b/hw/ppce500_pci.c @@ -89,6 +89,7 @@ static uint32_t pci_reg_read4(void *opaque, target_phys_addr_t addr) PPCE500PCIState *pci = opaque; unsigned long win; uint32_t value = 0; + int idx; win = addr & 0xfe0; @@ -97,18 +98,19 @@ static uint32_t pci_reg_read4(void *opaque, target_phys_addr_t addr) case PPCE500_PCI_OW2: case PPCE500_PCI_OW3: case PPCE500_PCI_OW4: + idx = (addr >> 5) & 0x7; switch (addr & 0xC) { case PCI_POTAR: - value = pci->pob[(addr >> 5) & 0x7].potar; + value = pci->pob[idx].potar; break; case PCI_POTEAR: - value = pci->pob[(addr >> 5) & 0x7].potear; + value = pci->pob[idx].potear; break; case PCI_POWBAR: - value = pci->pob[(addr >> 5) & 0x7].powbar; + value = pci->pob[idx].powbar; break; case PCI_POWAR: - value = pci->pob[(addr >> 5) & 0x7].powar; + value = pci->pob[idx].powar; break; default: break; @@ -118,18 +120,19 @@ static uint32_t pci_reg_read4(void *opaque, target_phys_addr_t addr) case PPCE500_PCI_IW3: case PPCE500_PCI_IW2: case PPCE500_PCI_IW1: + idx = ((addr >> 5) & 0x3) - 1; switch (addr & 0xC) { case PCI_PITAR: - value = pci->pib[(addr >> 5) & 0x3].pitar; + value = pci->pib[idx].pitar; break; case PCI_PIWBAR: - value = pci->pib[(addr >> 5) & 0x3].piwbar; + value = pci->pib[idx].piwbar; break; case PCI_PIWBEAR: - value = pci->pib[(addr >> 5) & 0x3].piwbear; + value = pci->pib[idx].piwbear; break; case PCI_PIWAR: - value = pci->pib[(addr >> 5) & 0x3].piwar; + value = pci->pib[idx].piwar; break; default: break; @@ -160,6 +163,7 @@ static void pci_reg_write4(void *opaque, target_phys_addr_t addr, { PPCE500PCIState *pci = opaque; unsigned long win; + int idx; win = addr & 0xfe0; @@ -171,18 +175,19 @@ static void pci_reg_write4(void *opaque, target_phys_addr_t addr, case PPCE500_PCI_OW2: case PPCE500_PCI_OW3: case PPCE500_PCI_OW4: + idx = (addr >> 5) & 0x7; switch (addr & 0xC) { case PCI_POTAR: - pci->pob[(addr >> 5) & 0x7].potar = value; + pci->pob[idx].potar = value; break; case PCI_POTEAR: - pci->pob[(addr >> 5) & 0x7].potear = value; + pci->pob[idx].potear = value; break; case PCI_POWBAR: - pci->pob[(addr >> 5) & 0x7].powbar = value; + pci->pob[idx].powbar = value; break; case PCI_POWAR: - pci->pob[(addr >> 5) & 0x7].powar = value; + pci->pob[idx].powar = value; break; default: break; @@ -192,18 +197,19 @@ static void pci_reg_write4(void *opaque, target_phys_addr_t addr, case PPCE500_PCI_IW3: case PPCE500_PCI_IW2: case PPCE500_PCI_IW1: + idx = ((addr >> 5) & 0x3) - 1; switch (addr & 0xC) { case PCI_PITAR: - pci->pib[(addr >> 5) & 0x3].pitar = value; + pci->pib[idx].pitar = value; break; case PCI_PIWBAR: - pci->pib[(addr >> 5) & 0x3].piwbar = value; + pci->pib[idx].piwbar = value; break; case PCI_PIWBEAR: - pci->pib[(addr >> 5) & 0x3].piwbear = value; + pci->pib[idx].piwbear = value; break; case PCI_PIWAR: - pci->pib[(addr >> 5) & 0x3].piwar = value; + pci->pib[idx].piwar = value; break; default: break; From e97c363638b32943afc4bd2845f4081496fabfbc Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 29 Sep 2011 21:39:10 +0000 Subject: [PATCH 03/25] pseries: Support SMT systems for KVM Book3S-HV Alex Graf has already made qemu support KVM for the pseries machine when using the Book3S-PR KVM variant (which runs the guest in usermode, emulating supervisor operations). This code allows gets us very close to also working with KVM Book3S-HV (using the hypervisor capabilities of recent POWER CPUs). This patch moves us another step towards Book3S-HV support by correctly handling SMT (multithreaded) POWER CPUs. There are two parts to this: * Querying KVM to check SMT capability, and if present, adjusting the cpu numbers that qemu assigns to cause KVM to assign guest threads to cores in the right way (this isn't automatic, because the POWER HV support has a limitation that different threads on a single core cannot be in different guests at the same time). * Correctly informing the guest OS of the SMT thread to core mappings via the device tree. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr.c | 24 +++++++++++++++++++++--- target-ppc/helper.c | 11 +++++++++++ target-ppc/kvm.c | 8 ++++++++ target-ppc/kvm_ppc.h | 6 ++++++ 4 files changed, 46 insertions(+), 3 deletions(-) diff --git a/hw/spapr.c b/hw/spapr.c index 63e5d336ea..c2675e1cc1 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -29,6 +29,9 @@ #include "elf.h" #include "net.h" #include "blockdev.h" +#include "cpus.h" +#include "kvm.h" +#include "kvm_ppc.h" #include "hw/boards.h" #include "hw/ppc.h" @@ -105,6 +108,7 @@ static void *spapr_create_fdt_skel(const char *cpu_model, uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)}; int i; char *modelname; + int smt = kvmppc_smt_threads(); #define _FDT(exp) \ do { \ @@ -164,13 +168,18 @@ static void *spapr_create_fdt_skel(const char *cpu_model, for (env = first_cpu; env != NULL; env = env->next_cpu) { int index = env->cpu_index; - uint32_t gserver_prop[] = {cpu_to_be32(index), 0}; /* HACK! */ + uint32_t servers_prop[smp_threads]; + uint32_t gservers_prop[smp_threads * 2]; char *nodename; uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40), 0xffffffff, 0xffffffff}; uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq() : TIMEBASE_FREQ; uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000; + if ((index % smt) != 0) { + continue; + } + if (asprintf(&nodename, "%s@%x", modelname, index) < 0) { fprintf(stderr, "Allocation failure\n"); exit(1); @@ -195,9 +204,18 @@ static void *spapr_create_fdt_skel(const char *cpu_model, pft_size_prop, sizeof(pft_size_prop)))); _FDT((fdt_property_string(fdt, "status", "okay"))); _FDT((fdt_property(fdt, "64-bit", NULL, 0))); - _FDT((fdt_property_cell(fdt, "ibm,ppc-interrupt-server#s", index))); + + /* Build interrupt servers and gservers properties */ + for (i = 0; i < smp_threads; i++) { + servers_prop[i] = cpu_to_be32(index + i); + /* Hack, direct the group queues back to cpu 0 */ + gservers_prop[i*2] = cpu_to_be32(index + i); + gservers_prop[i*2 + 1] = 0; + } + _FDT((fdt_property(fdt, "ibm,ppc-interrupt-server#s", + servers_prop, sizeof(servers_prop)))); _FDT((fdt_property(fdt, "ibm,ppc-interrupt-gserver#s", - gserver_prop, sizeof(gserver_prop)))); + gservers_prop, sizeof(gservers_prop)))); if (env->mmu_model & POWERPC_MMU_1TSEG) { _FDT((fdt_property(fdt, "ibm,processor-segment-sizes", diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 6339be3a75..137a494201 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -26,6 +26,8 @@ #include "helper_regs.h" #include "qemu-common.h" #include "kvm.h" +#include "kvm_ppc.h" +#include "cpus.h" //#define DEBUG_MMU //#define DEBUG_BATS @@ -3189,6 +3191,15 @@ CPUPPCState *cpu_ppc_init (const char *cpu_model) if (tcg_enabled()) { ppc_translate_init(); } + /* Adjust cpu index for SMT */ +#if !defined(CONFIG_USER_ONLY) + if (kvm_enabled()) { + int smt = kvmppc_smt_threads(); + + env->cpu_index = (env->cpu_index / smp_threads)*smt + + (env->cpu_index % smp_threads); + } +#endif /* !CONFIG_USER_ONLY */ env->cpu_model_str = cpu_model; cpu_ppc_register_internal(env, def); diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 75832d83b8..6c7ca6fc50 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -28,6 +28,7 @@ #include "kvm_ppc.h" #include "cpu.h" #include "device_tree.h" +#include "hw/spapr.h" #include "hw/sysbus.h" #include "hw/spapr.h" @@ -53,6 +54,7 @@ static int cap_interrupt_unset = false; static int cap_interrupt_level = false; static int cap_segstate; static int cap_booke_sregs; +static int cap_ppc_smt; /* XXX We have a race condition where we actually have a level triggered * interrupt, but the infrastructure can't expose that yet, so the guest @@ -76,6 +78,7 @@ int kvm_arch_init(KVMState *s) cap_interrupt_level = kvm_check_extension(s, KVM_CAP_PPC_IRQ_LEVEL); cap_segstate = kvm_check_extension(s, KVM_CAP_PPC_SEGSTATE); cap_booke_sregs = kvm_check_extension(s, KVM_CAP_PPC_BOOKE_SREGS); + cap_ppc_smt = kvm_check_extension(s, KVM_CAP_PPC_SMT); if (!cap_interrupt_level) { fprintf(stderr, "KVM: Couldn't find level irq capability. Expect the " @@ -750,6 +753,11 @@ fail: cpu_abort(env, "This KVM version does not support PAPR\n"); } +int kvmppc_smt_threads(void) +{ + return cap_ppc_smt ? cap_ppc_smt : 1; +} + bool kvm_arch_stop_on_emulation_error(CPUState *env) { return true; diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index c484e60bcb..c298411aa8 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -18,6 +18,7 @@ uint64_t kvmppc_get_clockfreq(void); int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len); int kvmppc_set_interrupt(CPUState *env, int irq, int level); void kvmppc_set_papr(CPUState *env); +int kvmppc_smt_threads(void); #else @@ -45,6 +46,11 @@ static inline void kvmppc_set_papr(CPUState *env) { } +static inline int kvmppc_smt_threads(void) +{ + return 1; +} + #endif #ifndef CONFIG_KVM From 354ac20a36a82a5ee09b0a6c8ba8655358a7597f Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 29 Sep 2011 21:39:11 +0000 Subject: [PATCH 04/25] pseries: Allow KVM Book3S-HV on PPC970 CPUS At present, using the hypervisor aware Book3S-HV KVM will only work with qemu on POWER7 CPUs. PPC970 CPUs also have hypervisor capability, but they lack the VRMA feature which makes assigning guest memory easier. In order to allow KVM Book3S-HV on PPC970, we need to specially allocate the first chunk of guest memory (the "Real Mode Area" or RMA), so that it is physically contiguous. Sufficiently recent host kernels allow such contiguous RMAs to be allocated, with a kvm capability advertising whether the feature is available and/or necessary on this hardware. This patch enables qemu to use this support, thus allowing kvm acceleration of pseries qemu machines on PPC970 hardware. Signed-off-by: Paul Mackerras Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- agraf: fix to use memory api --- hw/spapr.c | 56 ++++++++++++++++++++++++++++++++++---------- target-ppc/kvm.c | 44 ++++++++++++++++++++++++++++++++++ target-ppc/kvm_ppc.h | 8 +++++++ 3 files changed, 96 insertions(+), 12 deletions(-) diff --git a/hw/spapr.c b/hw/spapr.c index c2675e1cc1..193398b7a1 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -91,6 +91,7 @@ qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num) } static void *spapr_create_fdt_skel(const char *cpu_model, + target_phys_addr_t rma_size, target_phys_addr_t initrd_base, target_phys_addr_t initrd_size, const char *boot_device, @@ -99,7 +100,9 @@ static void *spapr_create_fdt_skel(const char *cpu_model, { void *fdt; CPUState *env; - uint64_t mem_reg_property[] = { 0, cpu_to_be64(ram_size) }; + uint64_t mem_reg_property_rma[] = { 0, cpu_to_be64(rma_size) }; + uint64_t mem_reg_property_nonrma[] = { cpu_to_be64(rma_size), + cpu_to_be64(ram_size - rma_size) }; uint32_t start_prop = cpu_to_be32(initrd_base); uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size); uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)}; @@ -145,15 +148,25 @@ static void *spapr_create_fdt_skel(const char *cpu_model, _FDT((fdt_end_node(fdt))); - /* memory node */ + /* memory node(s) */ _FDT((fdt_begin_node(fdt, "memory@0"))); _FDT((fdt_property_string(fdt, "device_type", "memory"))); - _FDT((fdt_property(fdt, "reg", - mem_reg_property, sizeof(mem_reg_property)))); - + _FDT((fdt_property(fdt, "reg", mem_reg_property_rma, + sizeof(mem_reg_property_rma)))); _FDT((fdt_end_node(fdt))); + if (ram_size > rma_size) { + char mem_name[32]; + + sprintf(mem_name, "memory@%" PRIx64, (uint64_t)rma_size); + _FDT((fdt_begin_node(fdt, mem_name))); + _FDT((fdt_property_string(fdt, "device_type", "memory"))); + _FDT((fdt_property(fdt, "reg", mem_reg_property_nonrma, + sizeof(mem_reg_property_nonrma)))); + _FDT((fdt_end_node(fdt))); + } + /* cpus */ _FDT((fdt_begin_node(fdt, "cpus"))); @@ -346,6 +359,7 @@ static void ppc_spapr_init(ram_addr_t ram_size, int i; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); + target_phys_addr_t rma_alloc_size, rma_size; uint32_t initrd_base; long kernel_size, initrd_size, fw_size; long pteg_shift = 17; @@ -354,10 +368,23 @@ static void ppc_spapr_init(ram_addr_t ram_size, spapr = g_malloc(sizeof(*spapr)); cpu_ppc_hypercall = emulate_spapr_hypercall; - /* We place the device tree just below either the top of RAM, or - * 2GB, so that it can be processed with 32-bit code if - * necessary */ - spapr->fdt_addr = MIN(ram_size, 0x80000000) - FDT_MAX_SIZE; + /* Allocate RMA if necessary */ + rma_alloc_size = kvmppc_alloc_rma("ppc_spapr.rma", sysmem); + + if (rma_alloc_size == -1) { + hw_error("qemu: Unable to create RMA\n"); + exit(1); + } + if (rma_alloc_size && (rma_alloc_size < ram_size)) { + rma_size = rma_alloc_size; + } else { + rma_size = ram_size; + } + + /* We place the device tree just below either the top of the RMA, + * or just below 2GB, whichever is lowere, so that it can be + * processed with 32-bit real mode code if necessary */ + spapr->fdt_addr = MIN(rma_size, 0x80000000) - FDT_MAX_SIZE; spapr->rtas_addr = spapr->fdt_addr - RTAS_MAX_SIZE; /* init CPUs */ @@ -382,8 +409,13 @@ static void ppc_spapr_init(ram_addr_t ram_size, /* allocate RAM */ spapr->ram_limit = ram_size; - memory_region_init_ram(ram, NULL, "ppc_spapr.ram", spapr->ram_limit); - memory_region_add_subregion(sysmem, 0, ram); + if (spapr->ram_limit > rma_alloc_size) { + ram_addr_t nonrma_base = rma_alloc_size; + ram_addr_t nonrma_size = spapr->ram_limit - rma_alloc_size; + + memory_region_init_ram(ram, NULL, "ppc_spapr.ram", nonrma_size); + memory_region_add_subregion(sysmem, nonrma_base, ram); + } /* allocate hash page table. For now we always make this 16mb, * later we should probably make it scale to the size of guest @@ -507,7 +539,7 @@ static void ppc_spapr_init(ram_addr_t ram_size, } /* Prepare the device tree */ - spapr->fdt_skel = spapr_create_fdt_skel(cpu_model, + spapr->fdt_skel = spapr_create_fdt_skel(cpu_model, rma_size, initrd_base, initrd_size, boot_device, kernel_cmdline, pteg_shift + 7); diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 6c7ca6fc50..fd17d23d2e 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -55,6 +55,7 @@ static int cap_interrupt_level = false; static int cap_segstate; static int cap_booke_sregs; static int cap_ppc_smt; +static int cap_ppc_rma; /* XXX We have a race condition where we actually have a level triggered * interrupt, but the infrastructure can't expose that yet, so the guest @@ -79,6 +80,7 @@ int kvm_arch_init(KVMState *s) cap_segstate = kvm_check_extension(s, KVM_CAP_PPC_SEGSTATE); cap_booke_sregs = kvm_check_extension(s, KVM_CAP_PPC_BOOKE_SREGS); cap_ppc_smt = kvm_check_extension(s, KVM_CAP_PPC_SMT); + cap_ppc_rma = kvm_check_extension(s, KVM_CAP_PPC_RMA); if (!cap_interrupt_level) { fprintf(stderr, "KVM: Couldn't find level irq capability. Expect the " @@ -758,6 +760,48 @@ int kvmppc_smt_threads(void) return cap_ppc_smt ? cap_ppc_smt : 1; } +off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem) +{ + void *rma; + off_t size; + int fd; + struct kvm_allocate_rma ret; + MemoryRegion *rma_region; + + /* If cap_ppc_rma == 0, contiguous RMA allocation is not supported + * if cap_ppc_rma == 1, contiguous RMA allocation is supported, but + * not necessary on this hardware + * if cap_ppc_rma == 2, contiguous RMA allocation is needed on this hardware + * + * FIXME: We should allow the user to force contiguous RMA + * allocation in the cap_ppc_rma==1 case. + */ + if (cap_ppc_rma < 2) { + return 0; + } + + fd = kvm_vm_ioctl(kvm_state, KVM_ALLOCATE_RMA, &ret); + if (fd < 0) { + fprintf(stderr, "KVM: Error on KVM_ALLOCATE_RMA: %s\n", + strerror(errno)); + return -1; + } + + size = MIN(ret.rma_size, 256ul << 20); + + rma = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + if (rma == MAP_FAILED) { + fprintf(stderr, "KVM: Error mapping RMA: %s\n", strerror(errno)); + return -1; + }; + + rma_region = g_new(MemoryRegion, 1); + memory_region_init_ram_ptr(rma_region, NULL, name, size, rma); + memory_region_add_subregion(sysmem, 0, rma_region); + + return size; +} + bool kvm_arch_stop_on_emulation_error(CPUState *env) { return true; diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index c298411aa8..82f32f449e 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -9,6 +9,8 @@ #ifndef __KVM_PPC_H__ #define __KVM_PPC_H__ +#include "memory.h" + void kvmppc_init(void); #ifdef CONFIG_KVM @@ -19,6 +21,7 @@ int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len); int kvmppc_set_interrupt(CPUState *env, int irq, int level); void kvmppc_set_papr(CPUState *env); int kvmppc_smt_threads(void); +off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem); #else @@ -51,6 +54,11 @@ static inline int kvmppc_smt_threads(void) return 1; } +static inline off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem) +{ + return 0; +} + #endif #ifndef CONFIG_KVM From 0f5cb2989f33059a70e8da335b62af5f27fabbe2 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 29 Sep 2011 21:39:12 +0000 Subject: [PATCH 05/25] pseries: Use Book3S-HV TCE acceleration capabilities The pseries machine of qemu implements the TCE mechanism used as a virtual IOMMU for the PAPR defined virtual IO devices. Because the PAPR spec only defines a small DMA address space, the guest VIO drivers need to update TCE mappings very frequently - the virtual network device is particularly bad. This means many slow exits to qemu to emulate the H_PUT_TCE hypercall. Sufficiently recent kernels allow this to be mitigated by implementing H_PUT_TCE in the host kernel. To make use of this, however, qemu needs to initialize the necessary TCE tables, and map them into itself so that the VIO device implementations can retrieve the mappings when they access guest memory (which is treated as a virtual DMA operation). This patch adds the necessary calls to use the KVM TCE acceleration. If the kernel does not support acceleration, or there is some other error creating the accelerated TCE table, then it will still fall back to full userspace TCE implementation. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr_vio.c | 8 ++++++- hw/spapr_vio.h | 1 + target-ppc/kvm.c | 54 ++++++++++++++++++++++++++++++++++++++++++++ target-ppc/kvm_ppc.h | 14 ++++++++++++ 4 files changed, 76 insertions(+), 1 deletion(-) diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index 35818e18f1..1da3032215 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -165,7 +165,13 @@ static void rtce_init(VIOsPAPRDevice *dev) * sizeof(VIOsPAPR_RTCE); if (size) { - dev->rtce_table = g_malloc0(size); + dev->rtce_table = kvmppc_create_spapr_tce(dev->reg, + dev->rtce_window_size, + &dev->kvmtce_fd); + + if (!dev->rtce_table) { + dev->rtce_table = g_malloc0(size); + } } } diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h index 4fe5f742c2..a325a5f4b3 100644 --- a/hw/spapr_vio.h +++ b/hw/spapr_vio.h @@ -57,6 +57,7 @@ typedef struct VIOsPAPRDevice { target_ulong signal_state; uint32_t rtce_window_size; VIOsPAPR_RTCE *rtce_table; + int kvmtce_fd; VIOsPAPR_CRQ crq; } VIOsPAPRDevice; diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index fd17d23d2e..06cad41de5 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -28,6 +28,7 @@ #include "kvm_ppc.h" #include "cpu.h" #include "device_tree.h" +#include "hw/sysbus.h" #include "hw/spapr.h" #include "hw/sysbus.h" @@ -56,6 +57,7 @@ static int cap_segstate; static int cap_booke_sregs; static int cap_ppc_smt; static int cap_ppc_rma; +static int cap_spapr_tce; /* XXX We have a race condition where we actually have a level triggered * interrupt, but the infrastructure can't expose that yet, so the guest @@ -81,6 +83,7 @@ int kvm_arch_init(KVMState *s) cap_booke_sregs = kvm_check_extension(s, KVM_CAP_PPC_BOOKE_SREGS); cap_ppc_smt = kvm_check_extension(s, KVM_CAP_PPC_SMT); cap_ppc_rma = kvm_check_extension(s, KVM_CAP_PPC_RMA); + cap_spapr_tce = kvm_check_extension(s, KVM_CAP_SPAPR_TCE); if (!cap_interrupt_level) { fprintf(stderr, "KVM: Couldn't find level irq capability. Expect the " @@ -802,6 +805,57 @@ off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem) return size; } +void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd) +{ + struct kvm_create_spapr_tce args = { + .liobn = liobn, + .window_size = window_size, + }; + long len; + int fd; + void *table; + + if (!cap_spapr_tce) { + return NULL; + } + + fd = kvm_vm_ioctl(kvm_state, KVM_CREATE_SPAPR_TCE, &args); + if (fd < 0) { + return NULL; + } + + len = (window_size / SPAPR_VIO_TCE_PAGE_SIZE) * sizeof(VIOsPAPR_RTCE); + /* FIXME: round this up to page size */ + + table = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0); + if (table == MAP_FAILED) { + close(fd); + return NULL; + } + + *pfd = fd; + return table; +} + +int kvmppc_remove_spapr_tce(void *table, int fd, uint32_t window_size) +{ + long len; + + if (fd < 0) { + return -1; + } + + len = (window_size / SPAPR_VIO_TCE_PAGE_SIZE)*sizeof(VIOsPAPR_RTCE); + if ((munmap(table, len) < 0) || + (close(fd) < 0)) { + fprintf(stderr, "KVM: Unexpected error removing KVM SPAPR TCE " + "table: %s", strerror(errno)); + /* Leak the table */ + } + + return 0; +} + bool kvm_arch_stop_on_emulation_error(CPUState *env) { return true; diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index 82f32f449e..87d1bdd5fd 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -22,6 +22,8 @@ int kvmppc_set_interrupt(CPUState *env, int irq, int level); void kvmppc_set_papr(CPUState *env); int kvmppc_smt_threads(void); off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem); +void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd); +int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size); #else @@ -59,6 +61,18 @@ static inline off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem) return 0; } +static inline void *kvmppc_create_spapr_tce(uint32_t liobn, + uint32_t window_size, int *fd) +{ + return NULL; +} + +static inline int kvmppc_remove_spapr_tce(void *table, int pfd, + uint32_t window_size) +{ + return -1; +} + #endif #ifndef CONFIG_KVM From bdcf9d6cd4ff987e58ba4f311ba7b1a33cf3ce5e Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 29 Sep 2011 21:39:13 +0000 Subject: [PATCH 06/25] pseries: Update SLOF firmware image This patch updates the SLOF submodule and precompiled image. The new SLOF versions contains two changes of note: * The previous SLOF has a bug in SCSI condition handling that was exposed by recent updates to qemu's SCSI emulation. This update fixes the bug. * The previous SLOF has a bug in its addressing of SCSI devices, which can be exposed under certain conditions. The new SLOF also fixes this. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- pc-bios/README | 2 +- pc-bios/slof.bin | Bin 579072 -> 578968 bytes roms/SLOF | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pc-bios/README b/pc-bios/README index 4d1d816fdb..32a438efc0 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -17,7 +17,7 @@ - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware implementation for certain IBM POWER hardware. The sources are at https://github.com/dgibson/SLOF, and the image currently in qemu is - built from git tag qemu-slof-20110323. + built from git tag qemu-slof-20110930. - The PXE roms come from the iPXE project. Built with BANNER_TIME 0. Sources available at http://ipxe.org. Vendor:Device ID -> ROM mapping: diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin index 22c4c7f5c448e3002aefecf3438f5d080586d666..b9d4f35053be2cd6f599bffddf0ee99627eb00a9 100644 GIT binary patch delta 2772 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 Date: Wed, 28 Sep 2011 05:54:05 +0000 Subject: [PATCH 07/25] Set an invalid-bits mask for each SPE instructions SPE instructions are defined by pairs. Currently, the invalid-bits mask is set for the first instruction, but the second one can have a different mask. example: GEN_SPE(efdcmpeq, efdcfs, 0x17, 0x0B, 0x00600000, 0x00180000, PPC_SPE_DOUBLE), Signed-off-by: Fabien Chouteau Signed-off-by: Alexander Graf --- target-ppc/translate.c | 482 ++++++++++++++++++++++------------------- 1 file changed, 262 insertions(+), 220 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 1e362fc238..99e995c7b6 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -205,8 +205,10 @@ typedef struct DisasContext { } DisasContext; struct opc_handler_t { - /* invalid bits */ - uint32_t inval; + /* invalid bits for instruction 1 (Rc(opcode) == 0) */ + uint32_t inval1; + /* invalid bits for instruction 2 (Rc(opcode) == 1) */ + uint32_t inval2; /* instruction type */ uint64_t type; /* extended instruction type */ @@ -478,7 +480,23 @@ static inline target_ulong MASK(uint32_t start, uint32_t end) .opc3 = op3, \ .pad = { 0, }, \ .handler = { \ - .inval = invl, \ + .inval1 = invl, \ + .type = _typ, \ + .type2 = _typ2, \ + .handler = &gen_##name, \ + .oname = stringify(name), \ + }, \ + .oname = stringify(name), \ +} +#define GEN_OPCODE_DUAL(name, op1, op2, op3, invl1, invl2, _typ, _typ2) \ +{ \ + .opc1 = op1, \ + .opc2 = op2, \ + .opc3 = op3, \ + .pad = { 0, }, \ + .handler = { \ + .inval1 = invl1, \ + .inval2 = invl2, \ .type = _typ, \ .type2 = _typ2, \ .handler = &gen_##name, \ @@ -493,7 +511,7 @@ static inline target_ulong MASK(uint32_t start, uint32_t end) .opc3 = op3, \ .pad = { 0, }, \ .handler = { \ - .inval = invl, \ + .inval1 = invl, \ .type = _typ, \ .type2 = _typ2, \ .handler = &gen_##name, \ @@ -509,7 +527,22 @@ static inline target_ulong MASK(uint32_t start, uint32_t end) .opc3 = op3, \ .pad = { 0, }, \ .handler = { \ - .inval = invl, \ + .inval1 = invl, \ + .type = _typ, \ + .type2 = _typ2, \ + .handler = &gen_##name, \ + }, \ + .oname = stringify(name), \ +} +#define GEN_OPCODE_DUAL(name, op1, op2, op3, invl1, invl2, _typ, _typ2) \ +{ \ + .opc1 = op1, \ + .opc2 = op2, \ + .opc3 = op3, \ + .pad = { 0, }, \ + .handler = { \ + .inval1 = invl1, \ + .inval2 = invl2, \ .type = _typ, \ .type2 = _typ2, \ .handler = &gen_##name, \ @@ -523,7 +556,7 @@ static inline target_ulong MASK(uint32_t start, uint32_t end) .opc3 = op3, \ .pad = { 0, }, \ .handler = { \ - .inval = invl, \ + .inval1 = invl, \ .type = _typ, \ .type2 = _typ2, \ .handler = &gen_##name, \ @@ -550,7 +583,8 @@ static void gen_invalid(DisasContext *ctx) } static opc_handler_t invalid_handler = { - .inval = 0xFFFFFFFF, + .inval1 = 0xFFFFFFFF, + .inval2 = 0xFFFFFFFF, .type = PPC_NONE, .type2 = PPC_NONE, .handler = gen_invalid, @@ -6693,7 +6727,7 @@ static inline void gen_store_gpr64(int reg, TCGv_i64 t) #endif } -#define GEN_SPE(name0, name1, opc2, opc3, inval, type) \ +#define GEN_SPE(name0, name1, opc2, opc3, inval0, inval1, type) \ static void glue(gen_, name0##_##name1)(DisasContext *ctx) \ { \ if (Rc(ctx->opcode)) \ @@ -7416,35 +7450,35 @@ static inline void gen_evmwsmiaa(DisasContext *ctx) tcg_temp_free_i64(tmp); } -GEN_SPE(evaddw, speundef, 0x00, 0x08, 0x00000000, PPC_SPE); //// -GEN_SPE(evaddiw, speundef, 0x01, 0x08, 0x00000000, PPC_SPE); -GEN_SPE(evsubfw, speundef, 0x02, 0x08, 0x00000000, PPC_SPE); //// -GEN_SPE(evsubifw, speundef, 0x03, 0x08, 0x00000000, PPC_SPE); -GEN_SPE(evabs, evneg, 0x04, 0x08, 0x0000F800, PPC_SPE); //// -GEN_SPE(evextsb, evextsh, 0x05, 0x08, 0x0000F800, PPC_SPE); //// -GEN_SPE(evrndw, evcntlzw, 0x06, 0x08, 0x0000F800, PPC_SPE); //// -GEN_SPE(evcntlsw, brinc, 0x07, 0x08, 0x00000000, PPC_SPE); // -GEN_SPE(evmra, speundef, 0x02, 0x13, 0x0000F800, PPC_SPE); -GEN_SPE(speundef, evand, 0x08, 0x08, 0x00000000, PPC_SPE); //// -GEN_SPE(evandc, speundef, 0x09, 0x08, 0x00000000, PPC_SPE); //// -GEN_SPE(evxor, evor, 0x0B, 0x08, 0x00000000, PPC_SPE); //// -GEN_SPE(evnor, eveqv, 0x0C, 0x08, 0x00000000, PPC_SPE); //// -GEN_SPE(evmwumi, evmwsmi, 0x0C, 0x11, 0x00000000, PPC_SPE); -GEN_SPE(evmwumia, evmwsmia, 0x1C, 0x11, 0x00000000, PPC_SPE); -GEN_SPE(evmwumiaa, evmwsmiaa, 0x0C, 0x15, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evorc, 0x0D, 0x08, 0x00000000, PPC_SPE); //// -GEN_SPE(evnand, speundef, 0x0F, 0x08, 0x00000000, PPC_SPE); //// -GEN_SPE(evsrwu, evsrws, 0x10, 0x08, 0x00000000, PPC_SPE); //// -GEN_SPE(evsrwiu, evsrwis, 0x11, 0x08, 0x00000000, PPC_SPE); -GEN_SPE(evslw, speundef, 0x12, 0x08, 0x00000000, PPC_SPE); //// -GEN_SPE(evslwi, speundef, 0x13, 0x08, 0x00000000, PPC_SPE); -GEN_SPE(evrlw, evsplati, 0x14, 0x08, 0x00000000, PPC_SPE); // -GEN_SPE(evrlwi, evsplatfi, 0x15, 0x08, 0x00000000, PPC_SPE); -GEN_SPE(evmergehi, evmergelo, 0x16, 0x08, 0x00000000, PPC_SPE); //// -GEN_SPE(evmergehilo, evmergelohi, 0x17, 0x08, 0x00000000, PPC_SPE); //// -GEN_SPE(evcmpgtu, evcmpgts, 0x18, 0x08, 0x00600000, PPC_SPE); //// -GEN_SPE(evcmpltu, evcmplts, 0x19, 0x08, 0x00600000, PPC_SPE); //// -GEN_SPE(evcmpeq, speundef, 0x1A, 0x08, 0x00600000, PPC_SPE); //// +GEN_SPE(evaddw, speundef, 0x00, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); //// +GEN_SPE(evaddiw, speundef, 0x01, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); +GEN_SPE(evsubfw, speundef, 0x02, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); //// +GEN_SPE(evsubifw, speundef, 0x03, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); +GEN_SPE(evabs, evneg, 0x04, 0x08, 0x0000F800, 0x0000F800, PPC_SPE); //// +GEN_SPE(evextsb, evextsh, 0x05, 0x08, 0x0000F800, 0x0000F800, PPC_SPE); //// +GEN_SPE(evrndw, evcntlzw, 0x06, 0x08, 0x0000F800, 0x0000F800, PPC_SPE); //// +GEN_SPE(evcntlsw, brinc, 0x07, 0x08, 0x0000F800, 0x00000000, PPC_SPE); // +GEN_SPE(evmra, speundef, 0x02, 0x13, 0x0000F800, 0xFFFFFFFF, PPC_SPE); +GEN_SPE(speundef, evand, 0x08, 0x08, 0xFFFFFFFF, 0x00000000, PPC_SPE); //// +GEN_SPE(evandc, speundef, 0x09, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); //// +GEN_SPE(evxor, evor, 0x0B, 0x08, 0x00000000, 0x00000000, PPC_SPE); //// +GEN_SPE(evnor, eveqv, 0x0C, 0x08, 0x00000000, 0x00000000, PPC_SPE); //// +GEN_SPE(evmwumi, evmwsmi, 0x0C, 0x11, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(evmwumia, evmwsmia, 0x1C, 0x11, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(evmwumiaa, evmwsmiaa, 0x0C, 0x15, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evorc, 0x0D, 0x08, 0xFFFFFFFF, 0x00000000, PPC_SPE); //// +GEN_SPE(evnand, speundef, 0x0F, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); //// +GEN_SPE(evsrwu, evsrws, 0x10, 0x08, 0x00000000, 0x00000000, PPC_SPE); //// +GEN_SPE(evsrwiu, evsrwis, 0x11, 0x08, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(evslw, speundef, 0x12, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); //// +GEN_SPE(evslwi, speundef, 0x13, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); +GEN_SPE(evrlw, evsplati, 0x14, 0x08, 0x00000000, 0x0000F800, PPC_SPE); // +GEN_SPE(evrlwi, evsplatfi, 0x15, 0x08, 0x00000000, 0x0000F800, PPC_SPE); +GEN_SPE(evmergehi, evmergelo, 0x16, 0x08, 0x00000000, 0x00000000, PPC_SPE); //// +GEN_SPE(evmergehilo, evmergelohi, 0x17, 0x08, 0x00000000, 0x00000000, PPC_SPE); //// +GEN_SPE(evcmpgtu, evcmpgts, 0x18, 0x08, 0x00600000, 0x00600000, PPC_SPE); //// +GEN_SPE(evcmpltu, evcmplts, 0x19, 0x08, 0x00600000, 0x00600000, PPC_SPE); //// +GEN_SPE(evcmpeq, speundef, 0x1A, 0x08, 0x00600000, 0xFFFFFFFF, PPC_SPE); //// /* SPE load and stores */ static inline void gen_addr_spe_imm_index(DisasContext *ctx, TCGv EA, int sh) @@ -7803,74 +7837,74 @@ GEN_SPEOP_LDST(evstwwo, 0x1E, 2); /* Multiply and add - TODO */ #if 0 -GEN_SPE(speundef, evmhessf, 0x01, 0x10, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhossf, 0x03, 0x10, 0x00000000, PPC_SPE); -GEN_SPE(evmheumi, evmhesmi, 0x04, 0x10, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhesmf, 0x05, 0x10, 0x00000000, PPC_SPE); -GEN_SPE(evmhoumi, evmhosmi, 0x06, 0x10, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhosmf, 0x07, 0x10, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhessfa, 0x11, 0x10, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhossfa, 0x13, 0x10, 0x00000000, PPC_SPE); -GEN_SPE(evmheumia, evmhesmia, 0x14, 0x10, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhesmfa, 0x15, 0x10, 0x00000000, PPC_SPE); -GEN_SPE(evmhoumia, evmhosmia, 0x16, 0x10, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhosmfa, 0x17, 0x10, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhessf, 0x01, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE);// +GEN_SPE(speundef, evmhossf, 0x03, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmheumi, evmhesmi, 0x04, 0x10, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhesmf, 0x05, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhoumi, evmhosmi, 0x06, 0x10, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhosmf, 0x07, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhessfa, 0x11, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhossfa, 0x13, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmheumia, evmhesmia, 0x14, 0x10, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhesmfa, 0x15, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhoumia, evmhosmia, 0x16, 0x10, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhosmfa, 0x17, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwhssf, 0x03, 0x11, 0x00000000, PPC_SPE); -GEN_SPE(evmwlumi, speundef, 0x04, 0x11, 0x00000000, PPC_SPE); -GEN_SPE(evmwhumi, evmwhsmi, 0x06, 0x11, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwhsmf, 0x07, 0x11, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwssf, 0x09, 0x11, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwsmf, 0x0D, 0x11, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwhssfa, 0x13, 0x11, 0x00000000, PPC_SPE); -GEN_SPE(evmwlumia, speundef, 0x14, 0x11, 0x00000000, PPC_SPE); -GEN_SPE(evmwhumia, evmwhsmia, 0x16, 0x11, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwhsmfa, 0x17, 0x11, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwssfa, 0x19, 0x11, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwsmfa, 0x1D, 0x11, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwhssf, 0x03, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmwlumi, speundef, 0x04, 0x11, 0x00000000, 0xFFFFFFFF, PPC_SPE); +GEN_SPE(evmwhumi, evmwhsmi, 0x06, 0x11, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwhsmf, 0x07, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwssf, 0x09, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwsmf, 0x0D, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwhssfa, 0x13, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmwlumia, speundef, 0x14, 0x11, 0x00000000, 0xFFFFFFFF, PPC_SPE); +GEN_SPE(evmwhumia, evmwhsmia, 0x16, 0x11, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwhsmfa, 0x17, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwssfa, 0x19, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwsmfa, 0x1D, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); -GEN_SPE(evadduiaaw, evaddsiaaw, 0x00, 0x13, 0x0000F800, PPC_SPE); -GEN_SPE(evsubfusiaaw, evsubfssiaaw, 0x01, 0x13, 0x0000F800, PPC_SPE); -GEN_SPE(evaddumiaaw, evaddsmiaaw, 0x04, 0x13, 0x0000F800, PPC_SPE); -GEN_SPE(evsubfumiaaw, evsubfsmiaaw, 0x05, 0x13, 0x0000F800, PPC_SPE); -GEN_SPE(evdivws, evdivwu, 0x06, 0x13, 0x00000000, PPC_SPE); +GEN_SPE(evadduiaaw, evaddsiaaw, 0x00, 0x13, 0x0000F800, 0x0000F800, PPC_SPE); +GEN_SPE(evsubfusiaaw, evsubfssiaaw, 0x01, 0x13, 0x0000F800, 0x0000F800, PPC_SPE); +GEN_SPE(evaddumiaaw, evaddsmiaaw, 0x04, 0x13, 0x0000F800, 0x0000F800, PPC_SPE); +GEN_SPE(evsubfumiaaw, evsubfsmiaaw, 0x05, 0x13, 0x0000F800, 0x0000F800, PPC_SPE); +GEN_SPE(evdivws, evdivwu, 0x06, 0x13, 0x00000000, 0x00000000, PPC_SPE); -GEN_SPE(evmheusiaaw, evmhessiaaw, 0x00, 0x14, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhessfaaw, 0x01, 0x14, 0x00000000, PPC_SPE); -GEN_SPE(evmhousiaaw, evmhossiaaw, 0x02, 0x14, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhossfaaw, 0x03, 0x14, 0x00000000, PPC_SPE); -GEN_SPE(evmheumiaaw, evmhesmiaaw, 0x04, 0x14, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhesmfaaw, 0x05, 0x14, 0x00000000, PPC_SPE); -GEN_SPE(evmhoumiaaw, evmhosmiaaw, 0x06, 0x14, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhosmfaaw, 0x07, 0x14, 0x00000000, PPC_SPE); -GEN_SPE(evmhegumiaa, evmhegsmiaa, 0x14, 0x14, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhegsmfaa, 0x15, 0x14, 0x00000000, PPC_SPE); -GEN_SPE(evmhogumiaa, evmhogsmiaa, 0x16, 0x14, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhogsmfaa, 0x17, 0x14, 0x00000000, PPC_SPE); +GEN_SPE(evmheusiaaw, evmhessiaaw, 0x00, 0x14, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhessfaaw, 0x01, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhousiaaw, evmhossiaaw, 0x02, 0x14, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhossfaaw, 0x03, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmheumiaaw, evmhesmiaaw, 0x04, 0x14, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhesmfaaw, 0x05, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhoumiaaw, evmhosmiaaw, 0x06, 0x14, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhosmfaaw, 0x07, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhegumiaa, evmhegsmiaa, 0x14, 0x14, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhegsmfaa, 0x15, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhogumiaa, evmhogsmiaa, 0x16, 0x14, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhogsmfaa, 0x17, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE); -GEN_SPE(evmwlusiaaw, evmwlssiaaw, 0x00, 0x15, 0x00000000, PPC_SPE); -GEN_SPE(evmwlumiaaw, evmwlsmiaaw, 0x04, 0x15, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwssfaa, 0x09, 0x15, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwsmfaa, 0x0D, 0x15, 0x00000000, PPC_SPE); +GEN_SPE(evmwlusiaaw, evmwlssiaaw, 0x00, 0x15, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(evmwlumiaaw, evmwlsmiaaw, 0x04, 0x15, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwssfaa, 0x09, 0x15, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwsmfaa, 0x0D, 0x15, 0xFFFFFFFF, 0x00000000, PPC_SPE); -GEN_SPE(evmheusianw, evmhessianw, 0x00, 0x16, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhessfanw, 0x01, 0x16, 0x00000000, PPC_SPE); -GEN_SPE(evmhousianw, evmhossianw, 0x02, 0x16, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhossfanw, 0x03, 0x16, 0x00000000, PPC_SPE); -GEN_SPE(evmheumianw, evmhesmianw, 0x04, 0x16, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhesmfanw, 0x05, 0x16, 0x00000000, PPC_SPE); -GEN_SPE(evmhoumianw, evmhosmianw, 0x06, 0x16, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhosmfanw, 0x07, 0x16, 0x00000000, PPC_SPE); -GEN_SPE(evmhegumian, evmhegsmian, 0x14, 0x16, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhegsmfan, 0x15, 0x16, 0x00000000, PPC_SPE); -GEN_SPE(evmhigumian, evmhigsmian, 0x16, 0x16, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhogsmfan, 0x17, 0x16, 0x00000000, PPC_SPE); +GEN_SPE(evmheusianw, evmhessianw, 0x00, 0x16, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhessfanw, 0x01, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhousianw, evmhossianw, 0x02, 0x16, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhossfanw, 0x03, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmheumianw, evmhesmianw, 0x04, 0x16, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhesmfanw, 0x05, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhoumianw, evmhosmianw, 0x06, 0x16, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhosmfanw, 0x07, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhegumian, evmhegsmian, 0x14, 0x16, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhegsmfan, 0x15, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhigumian, evmhigsmian, 0x16, 0x16, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhogsmfan, 0x17, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE); -GEN_SPE(evmwlusianw, evmwlssianw, 0x00, 0x17, 0x00000000, PPC_SPE); -GEN_SPE(evmwlumianw, evmwlsmianw, 0x04, 0x17, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwssfan, 0x09, 0x17, 0x00000000, PPC_SPE); -GEN_SPE(evmwumian, evmwsmian, 0x0C, 0x17, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwsmfan, 0x0D, 0x17, 0x00000000, PPC_SPE); +GEN_SPE(evmwlusianw, evmwlssianw, 0x00, 0x17, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(evmwlumianw, evmwlsmianw, 0x04, 0x17, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwssfan, 0x09, 0x17, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmwumian, evmwsmian, 0x0C, 0x17, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwsmfan, 0x0D, 0x17, 0xFFFFFFFF, 0x00000000, PPC_SPE); #endif /*** SPE floating-point extension ***/ @@ -8131,20 +8165,20 @@ GEN_SPEFPUOP_COMP_64(evfststlt); GEN_SPEFPUOP_COMP_64(evfststeq); /* Opcodes definitions */ -GEN_SPE(evfsadd, evfssub, 0x00, 0x0A, 0x00000000, PPC_SPE_SINGLE); // -GEN_SPE(evfsabs, evfsnabs, 0x02, 0x0A, 0x0000F800, PPC_SPE_SINGLE); // -GEN_SPE(evfsneg, speundef, 0x03, 0x0A, 0x0000F800, PPC_SPE_SINGLE); // -GEN_SPE(evfsmul, evfsdiv, 0x04, 0x0A, 0x00000000, PPC_SPE_SINGLE); // -GEN_SPE(evfscmpgt, evfscmplt, 0x06, 0x0A, 0x00600000, PPC_SPE_SINGLE); // -GEN_SPE(evfscmpeq, speundef, 0x07, 0x0A, 0x00600000, PPC_SPE_SINGLE); // -GEN_SPE(evfscfui, evfscfsi, 0x08, 0x0A, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(evfscfuf, evfscfsf, 0x09, 0x0A, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(evfsctui, evfsctsi, 0x0A, 0x0A, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(evfsctuf, evfsctsf, 0x0B, 0x0A, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(evfsctuiz, speundef, 0x0C, 0x0A, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(evfsctsiz, speundef, 0x0D, 0x0A, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(evfststgt, evfststlt, 0x0E, 0x0A, 0x00600000, PPC_SPE_SINGLE); // -GEN_SPE(evfststeq, speundef, 0x0F, 0x0A, 0x00600000, PPC_SPE_SINGLE); // +GEN_SPE(evfsadd, evfssub, 0x00, 0x0A, 0x00000000, 0x00000000, PPC_SPE_SINGLE); // +GEN_SPE(evfsabs, evfsnabs, 0x02, 0x0A, 0x0000F800, 0x0000F800, PPC_SPE_SINGLE); // +GEN_SPE(evfsneg, speundef, 0x03, 0x0A, 0x0000F800, 0xFFFFFFFF, PPC_SPE_SINGLE); // +GEN_SPE(evfsmul, evfsdiv, 0x04, 0x0A, 0x00000000, 0x00000000, PPC_SPE_SINGLE); // +GEN_SPE(evfscmpgt, evfscmplt, 0x06, 0x0A, 0x00600000, 0x00600000, PPC_SPE_SINGLE); // +GEN_SPE(evfscmpeq, speundef, 0x07, 0x0A, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE); // +GEN_SPE(evfscfui, evfscfsi, 0x08, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(evfscfuf, evfscfsf, 0x09, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(evfsctui, evfsctsi, 0x0A, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(evfsctuf, evfsctsf, 0x0B, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(evfsctuiz, speundef, 0x0C, 0x0A, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE); // +GEN_SPE(evfsctsiz, speundef, 0x0D, 0x0A, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE); // +GEN_SPE(evfststgt, evfststlt, 0x0E, 0x0A, 0x00600000, 0x00600000, PPC_SPE_SINGLE); // +GEN_SPE(evfststeq, speundef, 0x0F, 0x0A, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE); // /* Single precision floating-point operations */ /* Arithmetic */ @@ -8199,20 +8233,20 @@ GEN_SPEFPUOP_COMP_32(efststlt); GEN_SPEFPUOP_COMP_32(efststeq); /* Opcodes definitions */ -GEN_SPE(efsadd, efssub, 0x00, 0x0B, 0x00000000, PPC_SPE_SINGLE); // -GEN_SPE(efsabs, efsnabs, 0x02, 0x0B, 0x0000F800, PPC_SPE_SINGLE); // -GEN_SPE(efsneg, speundef, 0x03, 0x0B, 0x0000F800, PPC_SPE_SINGLE); // -GEN_SPE(efsmul, efsdiv, 0x04, 0x0B, 0x00000000, PPC_SPE_SINGLE); // -GEN_SPE(efscmpgt, efscmplt, 0x06, 0x0B, 0x00600000, PPC_SPE_SINGLE); // -GEN_SPE(efscmpeq, efscfd, 0x07, 0x0B, 0x00600000, PPC_SPE_SINGLE); // -GEN_SPE(efscfui, efscfsi, 0x08, 0x0B, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(efscfuf, efscfsf, 0x09, 0x0B, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(efsctui, efsctsi, 0x0A, 0x0B, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(efsctuf, efsctsf, 0x0B, 0x0B, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(efsctuiz, speundef, 0x0C, 0x0B, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(efsctsiz, speundef, 0x0D, 0x0B, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(efststgt, efststlt, 0x0E, 0x0B, 0x00600000, PPC_SPE_SINGLE); // -GEN_SPE(efststeq, speundef, 0x0F, 0x0B, 0x00600000, PPC_SPE_SINGLE); // +GEN_SPE(efsadd, efssub, 0x00, 0x0B, 0x00000000, 0x00000000, PPC_SPE_SINGLE); // +GEN_SPE(efsabs, efsnabs, 0x02, 0x0B, 0x0000F800, 0x0000F800, PPC_SPE_SINGLE); // +GEN_SPE(efsneg, speundef, 0x03, 0x0B, 0x0000F800, 0xFFFFFFFF, PPC_SPE_SINGLE); // +GEN_SPE(efsmul, efsdiv, 0x04, 0x0B, 0x00000000, 0x00000000, PPC_SPE_SINGLE); // +GEN_SPE(efscmpgt, efscmplt, 0x06, 0x0B, 0x00600000, 0x00600000, PPC_SPE_SINGLE); // +GEN_SPE(efscmpeq, efscfd, 0x07, 0x0B, 0x00600000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(efscfui, efscfsi, 0x08, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(efscfuf, efscfsf, 0x09, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(efsctui, efsctsi, 0x0A, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(efsctuf, efsctsf, 0x0B, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(efsctuiz, speundef, 0x0C, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE); // +GEN_SPE(efsctsiz, speundef, 0x0D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE); // +GEN_SPE(efststgt, efststlt, 0x0E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_SINGLE); // +GEN_SPE(efststeq, speundef, 0x0F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE); // /* Double precision floating-point operations */ /* Arithmetic */ @@ -8286,22 +8320,22 @@ GEN_SPEFPUOP_COMP_64(efdtstlt); GEN_SPEFPUOP_COMP_64(efdtsteq); /* Opcodes definitions */ -GEN_SPE(efdadd, efdsub, 0x10, 0x0B, 0x00000000, PPC_SPE_DOUBLE); // -GEN_SPE(efdcfuid, efdcfsid, 0x11, 0x0B, 0x00180000, PPC_SPE_DOUBLE); // -GEN_SPE(efdabs, efdnabs, 0x12, 0x0B, 0x0000F800, PPC_SPE_DOUBLE); // -GEN_SPE(efdneg, speundef, 0x13, 0x0B, 0x0000F800, PPC_SPE_DOUBLE); // -GEN_SPE(efdmul, efddiv, 0x14, 0x0B, 0x00000000, PPC_SPE_DOUBLE); // -GEN_SPE(efdctuidz, efdctsidz, 0x15, 0x0B, 0x00180000, PPC_SPE_DOUBLE); // -GEN_SPE(efdcmpgt, efdcmplt, 0x16, 0x0B, 0x00600000, PPC_SPE_DOUBLE); // -GEN_SPE(efdcmpeq, efdcfs, 0x17, 0x0B, 0x00600000, PPC_SPE_DOUBLE); // -GEN_SPE(efdcfui, efdcfsi, 0x18, 0x0B, 0x00180000, PPC_SPE_DOUBLE); // -GEN_SPE(efdcfuf, efdcfsf, 0x19, 0x0B, 0x00180000, PPC_SPE_DOUBLE); // -GEN_SPE(efdctui, efdctsi, 0x1A, 0x0B, 0x00180000, PPC_SPE_DOUBLE); // -GEN_SPE(efdctuf, efdctsf, 0x1B, 0x0B, 0x00180000, PPC_SPE_DOUBLE); // -GEN_SPE(efdctuiz, speundef, 0x1C, 0x0B, 0x00180000, PPC_SPE_DOUBLE); // -GEN_SPE(efdctsiz, speundef, 0x1D, 0x0B, 0x00180000, PPC_SPE_DOUBLE); // -GEN_SPE(efdtstgt, efdtstlt, 0x1E, 0x0B, 0x00600000, PPC_SPE_DOUBLE); // -GEN_SPE(efdtsteq, speundef, 0x1F, 0x0B, 0x00600000, PPC_SPE_DOUBLE); // +GEN_SPE(efdadd, efdsub, 0x10, 0x0B, 0x00000000, 0x00000000, PPC_SPE_DOUBLE); // +GEN_SPE(efdcfuid, efdcfsid, 0x11, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); // +GEN_SPE(efdabs, efdnabs, 0x12, 0x0B, 0x0000F800, 0x0000F800, PPC_SPE_DOUBLE); // +GEN_SPE(efdneg, speundef, 0x13, 0x0B, 0x0000F800, 0xFFFFFFFF, PPC_SPE_DOUBLE); // +GEN_SPE(efdmul, efddiv, 0x14, 0x0B, 0x00000000, 0x00000000, PPC_SPE_DOUBLE); // +GEN_SPE(efdctuidz, efdctsidz, 0x15, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); // +GEN_SPE(efdcmpgt, efdcmplt, 0x16, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE); // +GEN_SPE(efdcmpeq, efdcfs, 0x17, 0x0B, 0x00600000, 0x00180000, PPC_SPE_DOUBLE); // +GEN_SPE(efdcfui, efdcfsi, 0x18, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); // +GEN_SPE(efdcfuf, efdcfsf, 0x19, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); // +GEN_SPE(efdctui, efdctsi, 0x1A, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); // +GEN_SPE(efdctuf, efdctsf, 0x1B, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); // +GEN_SPE(efdctuiz, speundef, 0x1C, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE); // +GEN_SPE(efdctsiz, speundef, 0x1D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE); // +GEN_SPE(efdtstgt, efdtstlt, 0x1E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE); // +GEN_SPE(efdtsteq, speundef, 0x1F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_DOUBLE); // static opcode_t opcodes[] = { GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE), @@ -9070,84 +9104,84 @@ GEN_VAFORM_PAIRED(vsel, vperm, 21), GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23), #undef GEN_SPE -#define GEN_SPE(name0, name1, opc2, opc3, inval, type) \ -GEN_HANDLER(name0##_##name1, 0x04, opc2, opc3, inval, type) -GEN_SPE(evaddw, speundef, 0x00, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evaddiw, speundef, 0x01, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evsubfw, speundef, 0x02, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evsubifw, speundef, 0x03, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evabs, evneg, 0x04, 0x08, 0x0000F800, PPC_SPE), -GEN_SPE(evextsb, evextsh, 0x05, 0x08, 0x0000F800, PPC_SPE), -GEN_SPE(evrndw, evcntlzw, 0x06, 0x08, 0x0000F800, PPC_SPE), -GEN_SPE(evcntlsw, brinc, 0x07, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evmra, speundef, 0x02, 0x13, 0x0000F800, PPC_SPE), -GEN_SPE(speundef, evand, 0x08, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evandc, speundef, 0x09, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evxor, evor, 0x0B, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evnor, eveqv, 0x0C, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evmwumi, evmwsmi, 0x0C, 0x11, 0x00000000, PPC_SPE), -GEN_SPE(evmwumia, evmwsmia, 0x1C, 0x11, 0x00000000, PPC_SPE), -GEN_SPE(evmwumiaa, evmwsmiaa, 0x0C, 0x15, 0x00000000, PPC_SPE), -GEN_SPE(speundef, evorc, 0x0D, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evnand, speundef, 0x0F, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evsrwu, evsrws, 0x10, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evsrwiu, evsrwis, 0x11, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evslw, speundef, 0x12, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evslwi, speundef, 0x13, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evrlw, evsplati, 0x14, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evrlwi, evsplatfi, 0x15, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evmergehi, evmergelo, 0x16, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evmergehilo, evmergelohi, 0x17, 0x08, 0x00000000, PPC_SPE), -GEN_SPE(evcmpgtu, evcmpgts, 0x18, 0x08, 0x00600000, PPC_SPE), -GEN_SPE(evcmpltu, evcmplts, 0x19, 0x08, 0x00600000, PPC_SPE), -GEN_SPE(evcmpeq, speundef, 0x1A, 0x08, 0x00600000, PPC_SPE), +#define GEN_SPE(name0, name1, opc2, opc3, inval0, inval1, type) \ + GEN_OPCODE_DUAL(name0##_##name1, 0x04, opc2, opc3, inval0, inval1, type, PPC_NONE) +GEN_SPE(evaddw, speundef, 0x00, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(evaddiw, speundef, 0x01, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(evsubfw, speundef, 0x02, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(evsubifw, speundef, 0x03, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(evabs, evneg, 0x04, 0x08, 0x0000F800, 0x0000F800, PPC_SPE), +GEN_SPE(evextsb, evextsh, 0x05, 0x08, 0x0000F800, 0x0000F800, PPC_SPE), +GEN_SPE(evrndw, evcntlzw, 0x06, 0x08, 0x0000F800, 0x0000F800, PPC_SPE), +GEN_SPE(evcntlsw, brinc, 0x07, 0x08, 0x0000F800, 0x00000000, PPC_SPE), +GEN_SPE(evmra, speundef, 0x02, 0x13, 0x0000F800, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(speundef, evand, 0x08, 0x08, 0xFFFFFFFF, 0x00000000, PPC_SPE), +GEN_SPE(evandc, speundef, 0x09, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(evxor, evor, 0x0B, 0x08, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(evnor, eveqv, 0x0C, 0x08, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(evmwumi, evmwsmi, 0x0C, 0x11, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(evmwumia, evmwsmia, 0x1C, 0x11, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(evmwumiaa, evmwsmiaa, 0x0C, 0x15, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(speundef, evorc, 0x0D, 0x08, 0xFFFFFFFF, 0x00000000, PPC_SPE), +GEN_SPE(evnand, speundef, 0x0F, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(evsrwu, evsrws, 0x10, 0x08, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(evsrwiu, evsrwis, 0x11, 0x08, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(evslw, speundef, 0x12, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(evslwi, speundef, 0x13, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(evrlw, evsplati, 0x14, 0x08, 0x00000000, 0x0000F800, PPC_SPE), +GEN_SPE(evrlwi, evsplatfi, 0x15, 0x08, 0x00000000, 0x0000F800, PPC_SPE), +GEN_SPE(evmergehi, evmergelo, 0x16, 0x08, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(evmergehilo, evmergelohi, 0x17, 0x08, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(evcmpgtu, evcmpgts, 0x18, 0x08, 0x00600000, 0x00600000, PPC_SPE), +GEN_SPE(evcmpltu, evcmplts, 0x19, 0x08, 0x00600000, 0x00600000, PPC_SPE), +GEN_SPE(evcmpeq, speundef, 0x1A, 0x08, 0x00600000, 0xFFFFFFFF, PPC_SPE), -GEN_SPE(evfsadd, evfssub, 0x00, 0x0A, 0x00000000, PPC_SPE_SINGLE), -GEN_SPE(evfsabs, evfsnabs, 0x02, 0x0A, 0x0000F800, PPC_SPE_SINGLE), -GEN_SPE(evfsneg, speundef, 0x03, 0x0A, 0x0000F800, PPC_SPE_SINGLE), -GEN_SPE(evfsmul, evfsdiv, 0x04, 0x0A, 0x00000000, PPC_SPE_SINGLE), -GEN_SPE(evfscmpgt, evfscmplt, 0x06, 0x0A, 0x00600000, PPC_SPE_SINGLE), -GEN_SPE(evfscmpeq, speundef, 0x07, 0x0A, 0x00600000, PPC_SPE_SINGLE), -GEN_SPE(evfscfui, evfscfsi, 0x08, 0x0A, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(evfscfuf, evfscfsf, 0x09, 0x0A, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(evfsctui, evfsctsi, 0x0A, 0x0A, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(evfsctuf, evfsctsf, 0x0B, 0x0A, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(evfsctuiz, speundef, 0x0C, 0x0A, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(evfsctsiz, speundef, 0x0D, 0x0A, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(evfststgt, evfststlt, 0x0E, 0x0A, 0x00600000, PPC_SPE_SINGLE), -GEN_SPE(evfststeq, speundef, 0x0F, 0x0A, 0x00600000, PPC_SPE_SINGLE), +GEN_SPE(evfsadd, evfssub, 0x00, 0x0A, 0x00000000, 0x00000000, PPC_SPE_SINGLE), +GEN_SPE(evfsabs, evfsnabs, 0x02, 0x0A, 0x0000F800, 0x0000F800, PPC_SPE_SINGLE), +GEN_SPE(evfsneg, speundef, 0x03, 0x0A, 0x0000F800, 0xFFFFFFFF, PPC_SPE_SINGLE), +GEN_SPE(evfsmul, evfsdiv, 0x04, 0x0A, 0x00000000, 0x00000000, PPC_SPE_SINGLE), +GEN_SPE(evfscmpgt, evfscmplt, 0x06, 0x0A, 0x00600000, 0x00600000, PPC_SPE_SINGLE), +GEN_SPE(evfscmpeq, speundef, 0x07, 0x0A, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE), +GEN_SPE(evfscfui, evfscfsi, 0x08, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(evfscfuf, evfscfsf, 0x09, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(evfsctui, evfsctsi, 0x0A, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(evfsctuf, evfsctsf, 0x0B, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(evfsctuiz, speundef, 0x0C, 0x0A, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE), +GEN_SPE(evfsctsiz, speundef, 0x0D, 0x0A, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE), +GEN_SPE(evfststgt, evfststlt, 0x0E, 0x0A, 0x00600000, 0x00600000, PPC_SPE_SINGLE), +GEN_SPE(evfststeq, speundef, 0x0F, 0x0A, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE), -GEN_SPE(efsadd, efssub, 0x00, 0x0B, 0x00000000, PPC_SPE_SINGLE), -GEN_SPE(efsabs, efsnabs, 0x02, 0x0B, 0x0000F800, PPC_SPE_SINGLE), -GEN_SPE(efsneg, speundef, 0x03, 0x0B, 0x0000F800, PPC_SPE_SINGLE), -GEN_SPE(efsmul, efsdiv, 0x04, 0x0B, 0x00000000, PPC_SPE_SINGLE), -GEN_SPE(efscmpgt, efscmplt, 0x06, 0x0B, 0x00600000, PPC_SPE_SINGLE), -GEN_SPE(efscmpeq, efscfd, 0x07, 0x0B, 0x00600000, PPC_SPE_SINGLE), -GEN_SPE(efscfui, efscfsi, 0x08, 0x0B, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(efscfuf, efscfsf, 0x09, 0x0B, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(efsctui, efsctsi, 0x0A, 0x0B, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(efsctuf, efsctsf, 0x0B, 0x0B, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(efsctuiz, speundef, 0x0C, 0x0B, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(efsctsiz, speundef, 0x0D, 0x0B, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(efststgt, efststlt, 0x0E, 0x0B, 0x00600000, PPC_SPE_SINGLE), -GEN_SPE(efststeq, speundef, 0x0F, 0x0B, 0x00600000, PPC_SPE_SINGLE), +GEN_SPE(efsadd, efssub, 0x00, 0x0B, 0x00000000, 0x00000000, PPC_SPE_SINGLE), +GEN_SPE(efsabs, efsnabs, 0x02, 0x0B, 0x0000F800, 0x0000F800, PPC_SPE_SINGLE), +GEN_SPE(efsneg, speundef, 0x03, 0x0B, 0x0000F800, 0xFFFFFFFF, PPC_SPE_SINGLE), +GEN_SPE(efsmul, efsdiv, 0x04, 0x0B, 0x00000000, 0x00000000, PPC_SPE_SINGLE), +GEN_SPE(efscmpgt, efscmplt, 0x06, 0x0B, 0x00600000, 0x00600000, PPC_SPE_SINGLE), +GEN_SPE(efscmpeq, efscfd, 0x07, 0x0B, 0x00600000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(efscfui, efscfsi, 0x08, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(efscfuf, efscfsf, 0x09, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(efsctui, efsctsi, 0x0A, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(efsctuf, efsctsf, 0x0B, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(efsctuiz, speundef, 0x0C, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE), +GEN_SPE(efsctsiz, speundef, 0x0D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE), +GEN_SPE(efststgt, efststlt, 0x0E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_SINGLE), +GEN_SPE(efststeq, speundef, 0x0F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE), -GEN_SPE(efdadd, efdsub, 0x10, 0x0B, 0x00000000, PPC_SPE_DOUBLE), -GEN_SPE(efdcfuid, efdcfsid, 0x11, 0x0B, 0x00180000, PPC_SPE_DOUBLE), -GEN_SPE(efdabs, efdnabs, 0x12, 0x0B, 0x0000F800, PPC_SPE_DOUBLE), -GEN_SPE(efdneg, speundef, 0x13, 0x0B, 0x0000F800, PPC_SPE_DOUBLE), -GEN_SPE(efdmul, efddiv, 0x14, 0x0B, 0x00000000, PPC_SPE_DOUBLE), -GEN_SPE(efdctuidz, efdctsidz, 0x15, 0x0B, 0x00180000, PPC_SPE_DOUBLE), -GEN_SPE(efdcmpgt, efdcmplt, 0x16, 0x0B, 0x00600000, PPC_SPE_DOUBLE), -GEN_SPE(efdcmpeq, efdcfs, 0x17, 0x0B, 0x00600000, PPC_SPE_DOUBLE), -GEN_SPE(efdcfui, efdcfsi, 0x18, 0x0B, 0x00180000, PPC_SPE_DOUBLE), -GEN_SPE(efdcfuf, efdcfsf, 0x19, 0x0B, 0x00180000, PPC_SPE_DOUBLE), -GEN_SPE(efdctui, efdctsi, 0x1A, 0x0B, 0x00180000, PPC_SPE_DOUBLE), -GEN_SPE(efdctuf, efdctsf, 0x1B, 0x0B, 0x00180000, PPC_SPE_DOUBLE), -GEN_SPE(efdctuiz, speundef, 0x1C, 0x0B, 0x00180000, PPC_SPE_DOUBLE), -GEN_SPE(efdctsiz, speundef, 0x1D, 0x0B, 0x00180000, PPC_SPE_DOUBLE), -GEN_SPE(efdtstgt, efdtstlt, 0x1E, 0x0B, 0x00600000, PPC_SPE_DOUBLE), -GEN_SPE(efdtsteq, speundef, 0x1F, 0x0B, 0x00600000, PPC_SPE_DOUBLE), +GEN_SPE(efdadd, efdsub, 0x10, 0x0B, 0x00000000, 0x00000000, PPC_SPE_DOUBLE), +GEN_SPE(efdcfuid, efdcfsid, 0x11, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE), +GEN_SPE(efdabs, efdnabs, 0x12, 0x0B, 0x0000F800, 0x0000F800, PPC_SPE_DOUBLE), +GEN_SPE(efdneg, speundef, 0x13, 0x0B, 0x0000F800, 0xFFFFFFFF, PPC_SPE_DOUBLE), +GEN_SPE(efdmul, efddiv, 0x14, 0x0B, 0x00000000, 0x00000000, PPC_SPE_DOUBLE), +GEN_SPE(efdctuidz, efdctsidz, 0x15, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE), +GEN_SPE(efdcmpgt, efdcmplt, 0x16, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE), +GEN_SPE(efdcmpeq, efdcfs, 0x17, 0x0B, 0x00600000, 0x00180000, PPC_SPE_DOUBLE), +GEN_SPE(efdcfui, efdcfsi, 0x18, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE), +GEN_SPE(efdcfuf, efdcfsf, 0x19, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE), +GEN_SPE(efdctui, efdctsi, 0x1A, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE), +GEN_SPE(efdctuf, efdctsf, 0x1B, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE), +GEN_SPE(efdctuiz, speundef, 0x1C, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE), +GEN_SPE(efdctsiz, speundef, 0x1D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE), +GEN_SPE(efdtstgt, efdtstlt, 0x1E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE), +GEN_SPE(efdtsteq, speundef, 0x1F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_DOUBLE), #undef GEN_SPEOP_LDST #define GEN_SPEOP_LDST(name, opc2, sh) \ @@ -9484,11 +9518,19 @@ static inline void gen_intermediate_code_internal(CPUState *env, opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, (int)msr_ir); } } else { - if (unlikely((ctx.opcode & handler->inval) != 0)) { + uint32_t inval; + + if (unlikely(handler->type & (PPC_SPE | PPC_SPE_SINGLE | PPC_SPE_DOUBLE) && Rc(ctx.opcode))) { + inval = handler->inval2; + } else { + inval = handler->inval1; + } + + if (unlikely((ctx.opcode & inval) != 0)) { if (qemu_log_enabled()) { qemu_log("invalid bits: %08x for opcode: " "%02x - %02x - %02x (%08x) " TARGET_FMT_lx "\n", - ctx.opcode & handler->inval, opc1(ctx.opcode), + ctx.opcode & inval, opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), ctx.opcode, ctx.nip - 4); } From 9bc884b741d3ab5bc3471a5cbccc38480676bf2b Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 10 Oct 2011 18:31:00 +0000 Subject: [PATCH 08/25] ppc: Generalize the kvmppc_get_clockfreq() function Currently the kvmppc_get_clockfreq() function reads the host's clock frequency from /proc/device-tree, which is useful to past to the guest in KVM setups. However, there are some other host properties advertised in the device tree which can also be relevant to the guests. This patch, therefore, replaces kvmppc_get_clockfreq() which can retrieve any named, single integer property from the host device tree's CPU node. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/kvm.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 06cad41de5..c48cd76b7c 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -650,37 +650,50 @@ static int kvmppc_find_cpu_dt(char *buf, int buf_len) return 0; } -uint64_t kvmppc_get_clockfreq(void) +/* Read a CPU node property from the host device tree that's a single + * integer (32-bit or 64-bit). Returns 0 if anything goes wrong + * (can't find or open the property, or doesn't understand the + * format) */ +static uint64_t kvmppc_read_int_cpu_dt(const char *propname) { - char buf[512]; - uint32_t tb[2]; + char buf[PATH_MAX]; + union { + uint32_t v32; + uint64_t v64; + } u; FILE *f; int len; if (kvmppc_find_cpu_dt(buf, sizeof(buf))) { - return 0; + return -1; } - strncat(buf, "/clock-frequency", sizeof(buf) - strlen(buf)); + strncat(buf, "/", sizeof(buf) - strlen(buf)); + strncat(buf, propname, sizeof(buf) - strlen(buf)); f = fopen(buf, "rb"); if (!f) { return -1; } - len = fread(tb, sizeof(tb[0]), 2, f); + len = fread(&u, 1, sizeof(u), f); fclose(f); switch (len) { - case 1: - /* freq is only a single cell */ - return tb[0]; - case 2: - return *(uint64_t*)tb; + case 4: + /* property is a 32-bit quantity */ + return be32_to_cpu(u.v32); + case 8: + return be64_to_cpu(u.v64); } return 0; } +uint64_t kvmppc_get_clockfreq(void) +{ + return kvmppc_read_int_cpu_dt("clock-frequency"); +} + int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len) { uint32_t *hc = (uint32_t*)buf; From 6659394fa1fa20aa640efa42c8fa5ee6994b6286 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 10 Oct 2011 18:31:01 +0000 Subject: [PATCH 09/25] pseries: Add device tree properties for VMX/VSX and DFP under kvm Sufficiently recent PAPR specifications define properties "ibm,vmx" and "ibm,dfp" on the CPU node which advertise whether the VMX vector extensions (or the later VSX version) and/or the Decimal Floating Point operations from IBM's recent POWER CPUs are available. Currently we do not put these in the guest device tree and the guest kernel will consequently assume they are not available. This is good, because they are not supported under TCG. VMX is similar enough to Altivec that it might be trivial to support, but VSX and DFP would both require significant work to support in TCG. However, when running under kvm on a host which supports these instructions, there's no reason not to let the guest use them. This patch, therefore, checks for the relevant support on the host CPU and, if present, advertises them to the guest as well. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr.c | 17 +++++++++++++++++ target-ppc/kvm.c | 10 ++++++++++ target-ppc/kvm_ppc.h | 12 ++++++++++++ 3 files changed, 39 insertions(+) diff --git a/hw/spapr.c b/hw/spapr.c index 193398b7a1..4d2a55e355 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -188,6 +188,8 @@ static void *spapr_create_fdt_skel(const char *cpu_model, 0xffffffff, 0xffffffff}; uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq() : TIMEBASE_FREQ; uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000; + uint32_t vmx = kvm_enabled() ? kvmppc_get_vmx() : 0; + uint32_t dfp = kvm_enabled() ? kvmppc_get_dfp() : 0; if ((index % smt) != 0) { continue; @@ -235,6 +237,21 @@ static void *spapr_create_fdt_skel(const char *cpu_model, segs, sizeof(segs)))); } + /* Advertise VMX/VSX (vector extensions) if available + * 0 / no property == no vector extensions + * 1 == VMX / Altivec available + * 2 == VSX available */ + if (vmx) { + _FDT((fdt_property_cell(fdt, "ibm,vmx", vmx))); + } + + /* Advertise DFP (Decimal Floating Point) if available + * 0 / no property == no DFP + * 1 == DFP available */ + if (dfp) { + _FDT((fdt_property_cell(fdt, "ibm,dfp", dfp))); + } + _FDT((fdt_end_node(fdt))); } diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index c48cd76b7c..96139acb23 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -694,6 +694,16 @@ uint64_t kvmppc_get_clockfreq(void) return kvmppc_read_int_cpu_dt("clock-frequency"); } +uint32_t kvmppc_get_vmx(void) +{ + return kvmppc_read_int_cpu_dt("ibm,vmx"); +} + +uint32_t kvmppc_get_dfp(void) +{ + return kvmppc_read_int_cpu_dt("ibm,dfp"); +} + int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len) { uint32_t *hc = (uint32_t*)buf; diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index 87d1bdd5fd..955729a1cf 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -17,6 +17,8 @@ void kvmppc_init(void); uint32_t kvmppc_get_tbfreq(void); uint64_t kvmppc_get_clockfreq(void); +uint32_t kvmppc_get_vmx(void); +uint32_t kvmppc_get_dfp(void); int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len); int kvmppc_set_interrupt(CPUState *env, int irq, int level); void kvmppc_set_papr(CPUState *env); @@ -37,6 +39,16 @@ static inline uint64_t kvmppc_get_clockfreq(void) return 0; } +static inline uint32_t kvmppc_get_vmx(void) +{ + return 0; +} + +static inline uint32_t kvmppc_get_dfp(void) +{ + return 0; +} + static inline int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len) { return -1; From d20dfdd4d21d7cae2cbc29e91674ea45f4a025d6 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 12 Oct 2011 19:10:30 +0000 Subject: [PATCH 10/25] pseries: Update SLOF firmware image This patch is a general update to the SLOF firmware image used on the pseries machine. This doesn't contain updates for specific features but contains a number of bugfixes and enhancements in the main SLOF tree from Thomas Huth. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- pc-bios/README | 2 +- pc-bios/slof.bin | Bin 578968 -> 738744 bytes roms/SLOF | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pc-bios/README b/pc-bios/README index 32a438efc0..0668559842 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -17,7 +17,7 @@ - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware implementation for certain IBM POWER hardware. The sources are at https://github.com/dgibson/SLOF, and the image currently in qemu is - built from git tag qemu-slof-20110930. + built from git tag qemu-slof-20111013. - The PXE roms come from the iPXE project. Built with BANNER_TIME 0. Sources available at http://ipxe.org. Vendor:Device ID -> ROM mapping: diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin index b9d4f35053be2cd6f599bffddf0ee99627eb00a9..1e84582cc695ff6e5973e045ef31ca951ca15c79 100644 GIT binary patch delta 225247 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 IDmC;200DPqZvX%Q delta 63814 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 diff --git a/roms/SLOF b/roms/SLOF index b94bde008b..32e3430c01 160000 --- a/roms/SLOF +++ b/roms/SLOF @@ -1 +1 @@ -Subproject commit b94bde008b0d49ec4bfe933e110d0952d032ac28 +Subproject commit 32e3430c018ceb8413cb808477449d1968c42497 From be40edcd87b8493cdf691dbe77049e0d9644dcc1 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 12 Oct 2011 22:40:31 +0000 Subject: [PATCH 11/25] ppc: Remove broken partial PVR matching The ppc target contains a ppc_find_by_pvr() function, which looks up a CPU spec based on a PVR (that is, based on the value in the target cpu's Processor Version Register). PVR values contain information on both the cpu model (upper 16 bits, usually) and on the precise revision (low 16 bits, usually). ppc_find_by_pvr, as well as making exact PVR matches, attempts to find "close" PVR matches, when we don't have a CPU spec for the exact revision specified. This sounds like a good idea, execpt that the current logic is completely nonsensical. It seems to assume CPU families are subdivided bit by bit in the PVR in a way they just aren't. Specifically, it requires a match on all bits of the specified pvr up to the last non-zero bit. This has the bizarre effect that when the low bits are simply a sequential revision number (a common though not universal pattern), then odd specified revisions must be matched exactly, whereas even specified revisions will also match the next odd revision, likewise for powers of 4, 8 and so forth. To correctly do inexact matching we'd need to re-organize the table of CPU specs to include a mask showing what PVR range the spec is compatible with (similar to the cputable code in the Linux kernel). For now, just remove the bogosity by only permitting exact PVR matches. That at least makes the matching simple and consistent. If we need inexact matching we can add the necessary per-subfamily masks later. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 36 ++++++------------------------------ 1 file changed, 6 insertions(+), 30 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index ca0d8525c8..73b49cfd6e 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -10043,40 +10043,16 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def) static const ppc_def_t *ppc_find_by_pvr (uint32_t pvr) { - const ppc_def_t *ret; - uint32_t pvr_rev; - int i, best, match, best_match, max; + int i; - ret = NULL; - max = ARRAY_SIZE(ppc_defs); - best = -1; - pvr_rev = pvr & 0xFFFF; - /* We want all specified bits to match */ - best_match = 32 - ctz32(pvr_rev); - for (i = 0; i < max; i++) { - /* We check that the 16 higher bits are the same to ensure the CPU - * model will be the choosen one. - */ - if (((pvr ^ ppc_defs[i].pvr) >> 16) == 0) { - /* We want as much as possible of the low-level 16 bits - * to be the same but we allow inexact matches. - */ - match = clz32(pvr_rev ^ (ppc_defs[i].pvr & 0xFFFF)); - /* We check '>=' instead of '>' because the PPC_defs table - * is ordered by increasing revision. - * Then, we will match the higher revision compatible - * with the requested PVR - */ - if (match >= best_match) { - best = i; - best_match = match; - } + for (i = 0; i < ARRAY_SIZE(ppc_defs); i++) { + /* If we have an exact match, we're done */ + if (pvr == ppc_defs[i].pvr) { + return &ppc_defs[i]; } } - if (best != -1) - ret = &ppc_defs[best]; - return ret; + return NULL; } #include From a1e985833cde3208b0f57c4c7e640b60fbc6c54d Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 12 Oct 2011 22:40:32 +0000 Subject: [PATCH 12/25] ppc: First cut implementation of -cpu host For convenience with kvm, x86 allows the user to specify -cpu host on the qemu command line, which means make the guest cpu the same as the host cpu. This patch implements the same option for ppc targets. For now, this just read the host PVR (Processor Version Register) and selects one of our existing CPU specs based on it. This means that the option will not work if the host cpu is not supported by TCG, even if that wouldn't matter for use under kvm. In future, we can extend this in future to override parts of the cpu spec based on information obtained from the host (via /proc/cpuinfo, the host device tree, or explicit KVM calls). That will let us handle cases where the real kvm-virtualized CPU doesn't behave exactly like the TCG-emulated CPU. With appropriate annotation of the CPU specs we'll also then be able to use host cpus under kvm even when there isn't a matching full TCG model. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/cpu.h | 1 + target-ppc/kvm.c | 19 +++++++++++++++++++ target-ppc/kvm_ppc.h | 6 ++++++ target-ppc/translate_init.c | 8 +++++++- 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 3f77e308a6..8e5c85c28e 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1107,6 +1107,7 @@ void ppc_store_msr (CPUPPCState *env, target_ulong value); void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf); +const ppc_def_t *ppc_find_by_pvr(uint32_t pvr); const ppc_def_t *cpu_ppc_find_by_name (const char *name); int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def); diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 96139acb23..313c7b2af2 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -879,6 +879,25 @@ int kvmppc_remove_spapr_tce(void *table, int fd, uint32_t window_size) return 0; } +static inline uint32_t mfpvr(void) +{ + uint32_t pvr; + + asm ("mfpvr %0" + : "=r"(pvr)); + return pvr; +} + +const ppc_def_t *kvmppc_host_cpu_def(void) +{ + uint32_t host_pvr = mfpvr(); + const ppc_def_t *base_spec; + + base_spec = ppc_find_by_pvr(host_pvr); + + return base_spec; +} + bool kvm_arch_stop_on_emulation_error(CPUState *env) { return true; diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index 955729a1cf..b0d6fb667e 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -26,6 +26,7 @@ int kvmppc_smt_threads(void); off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem); void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd); int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size); +const ppc_def_t *kvmppc_host_cpu_def(void); #else @@ -85,6 +86,11 @@ static inline int kvmppc_remove_spapr_tce(void *table, int pfd, return -1; } +static inline const ppc_def_t *kvmppc_host_cpu_def(void) +{ + return NULL; +} + #endif #ifndef CONFIG_KVM diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 73b49cfd6e..62f0a6b867 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -24,6 +24,8 @@ #include "dis-asm.h" #include "gdbstub.h" +#include +#include "kvm_ppc.h" //#define PPC_DUMP_CPU //#define PPC_DEBUG_SPR @@ -10041,7 +10043,7 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def) return 0; } -static const ppc_def_t *ppc_find_by_pvr (uint32_t pvr) +const ppc_def_t *ppc_find_by_pvr(uint32_t pvr) { int i; @@ -10063,6 +10065,10 @@ const ppc_def_t *cpu_ppc_find_by_name (const char *name) const char *p; int i, max, len; + if (kvm_enabled() && (strcasecmp(name, "host") == 0)) { + return kvmppc_host_cpu_def(); + } + /* Check if the given name is a PVR */ len = strlen(name); if (len == 10 && name[0] == '0' && name[1] == 'x') { From 37e305ce167279307335b069bff7e254b858fa6b Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 12 Oct 2011 22:40:33 +0000 Subject: [PATCH 13/25] ppc: Add cpu defs for POWER7 revisions 2.1 and 2.3 This patch adds cpu specs to the table for POWER7 revisions 2.1 and 2.3. This allows -cpu host to be used on these host cpus. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 62f0a6b867..7de097d945 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7333,6 +7333,8 @@ enum { CPU_POWERPC_POWER6A = 0x0F000002, #define CPU_POWERPC_POWER7 CPU_POWERPC_POWER7_v20 CPU_POWERPC_POWER7_v20 = 0x003F0200, + CPU_POWERPC_POWER7_v21 = 0x003F0201, + CPU_POWERPC_POWER7_v23 = 0x003F0203, CPU_POWERPC_970 = 0x00390202, #define CPU_POWERPC_970FX CPU_POWERPC_970FX_v31 CPU_POWERPC_970FX_v10 = 0x00391100, @@ -9139,6 +9141,8 @@ static const ppc_def_t ppc_defs[] = { /* POWER7 */ POWERPC_DEF("POWER7", CPU_POWERPC_POWER7, POWER7), POWERPC_DEF("POWER7_v2.0", CPU_POWERPC_POWER7_v20, POWER7), + POWERPC_DEF("POWER7_v2.1", CPU_POWERPC_POWER7_v21, POWER7), + POWERPC_DEF("POWER7_v2.3", CPU_POWERPC_POWER7_v23, POWER7), /* PowerPC 970 */ POWERPC_DEF("970", CPU_POWERPC_970, 970), /* PowerPC 970FX (G5) */ From 6b7a2cf6d93294a4e7c79fe101d31fc19d04fb48 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 12 Oct 2011 22:40:34 +0000 Subject: [PATCH 14/25] pseries: Under kvm use guest cpu = host cpu by default Now that we've implemented -cpu host for ppc, this patch updates the pseries machine to use the host cpu as the guest cpu by default when running under KVM. This is important because under KVM Book3S-HV the guest cpu _cannot_ be of a different type to the host cpu (at the moment KVM Book3S-HV will silently virtualize the host cpu instead of whatever was requested, but in future it is likely to simply refuse to run the VM if a cpu model other than the host's is requested). Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/spapr.c b/hw/spapr.c index 4d2a55e355..08c7399fef 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -406,7 +406,7 @@ static void ppc_spapr_init(ram_addr_t ram_size, /* init CPUs */ if (cpu_model == NULL) { - cpu_model = "POWER7"; + cpu_model = kvm_enabled() ? "host" : "POWER7"; } for (i = 0; i < smp_cpus; i++) { env = cpu_init(cpu_model); From 8b242eba641a6106db2d3b0356687f8e7e08e568 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 18 Oct 2011 01:46:08 +0200 Subject: [PATCH 15/25] PPC: Bump qemu-system-ppc to 64-bit physical address space Some 32-bit PPC CPUs can use up to 36 bit of physical address space. Treat them accordingly in the qemu-system-ppc binary type. Signed-off-by: Alexander Graf --- configure | 2 +- target-ppc/cpu.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 4f87e0a43b..f8dd4db6c5 100755 --- a/configure +++ b/configure @@ -3309,7 +3309,7 @@ case "$target_arch2" in ;; ppc) gdb_xml_files="power-core.xml power-fpu.xml power-altivec.xml power-spe.xml" - target_phys_bits=32 + target_phys_bits=64 target_nptl="yes" target_libs_softmmu="$fdt_libs" ;; diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 8e5c85c28e..f36f375596 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -66,7 +66,7 @@ #define TARGET_PAGE_BITS 12 #endif /* defined(TARGET_PPCEMB) */ -#define TARGET_PHYS_ADDR_SPACE_BITS 32 +#define TARGET_PHYS_ADDR_SPACE_BITS 36 #define TARGET_VIRT_ADDR_SPACE_BITS 32 #endif /* defined (TARGET_PPC64) */ From f0ad8c340145b246982885addef1aac183790706 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 18 Oct 2011 02:00:51 +0200 Subject: [PATCH 16/25] PPC: Disable non-440 CPUs for ppcemb target The sole reason we have the ppcemb target is to support MMUs that have less than the usual 4k possible page size. There are very few of these chips and I don't want to add additional QA and testing burden to everyone to ensure that code still works when TARGET_PAGE_SIZE is not 4k. So this patch disables all CPUs except for MMU_BOOKE capable ones from the ppcemb target. Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 7de097d945..f0ae1d1764 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -10047,11 +10047,27 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def) return 0; } +static bool ppc_cpu_usable(const ppc_def_t *def) +{ +#if defined(TARGET_PPCEMB) + /* When using the ppcemb target, we only support 440 style cores */ + if (def->mmu_model != POWERPC_MMU_BOOKE) { + return false; + } +#endif + + return true; +} + const ppc_def_t *ppc_find_by_pvr(uint32_t pvr) { int i; for (i = 0; i < ARRAY_SIZE(ppc_defs); i++) { + if (!ppc_cpu_usable(&ppc_defs[i])) { + continue; + } + /* If we have an exact match, we're done */ if (pvr == ppc_defs[i].pvr) { return &ppc_defs[i]; @@ -10091,6 +10107,10 @@ const ppc_def_t *cpu_ppc_find_by_name (const char *name) ret = NULL; max = ARRAY_SIZE(ppc_defs); for (i = 0; i < max; i++) { + if (!ppc_cpu_usable(&ppc_defs[i])) { + continue; + } + if (strcasecmp(name, ppc_defs[i].name) == 0) { ret = &ppc_defs[i]; break; @@ -10106,6 +10126,10 @@ void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf) max = ARRAY_SIZE(ppc_defs); for (i = 0; i < max; i++) { + if (!ppc_cpu_usable(&ppc_defs[i])) { + continue; + } + (*cpu_fprintf)(f, "PowerPC %-16s PVR %08x\n", ppc_defs[i].name, ppc_defs[i].pvr); } From 55f7d4b09e0bd1f6e5875fe0a5a58852999e4e92 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Sun, 16 Oct 2011 19:26:17 +0000 Subject: [PATCH 17/25] ppc: Avoid decrementer related kvm exits In __cpu_ppc_store_decr(), we set up a regular timer used to trigger decrementer interrupts. This is necessary to implement the decrementer properly under TCG, but is unnecessary under KVM (true for both Book3S-PR and Book3S-HV KVM variants), because the kernel handles generating and delivering decrementer exceptions. Under kvm, in fact, the timer causes expensive and unnecessary exits from kvm to qemu. This patch, therefore, disables setting the timer when kvm is in use. Signed-off-by: Anton Blanchard Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/ppc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/ppc.c b/hw/ppc.c index 25b59dddaa..d29af0bb35 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -662,6 +662,12 @@ static void __cpu_ppc_store_decr (CPUState *env, uint64_t *nextp, LOG_TB("%s: %08" PRIx32 " => %08" PRIx32 "\n", __func__, decr, value); + + if (kvm_enabled()) { + /* KVM handles decrementer exceptions, we don't need our own timer */ + return; + } + now = qemu_get_clock_ns(vm_clock); next = now + muldiv64(value, get_ticks_per_sec(), tb_env->decr_freq); if (is_excp) { From f90a9d02401eeeec18a122b61ccccb91244f321c Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 18 Oct 2011 02:10:36 +0200 Subject: [PATCH 18/25] PPC: Fail configure when libfdt is not available We have several targets in the PPC tree now that basically require libfdt to function properly, namely the pseries and the e500 targets. This dependency will rather increase than decrease in the future, so I want to make sure that people building shiny new 1.0 actually have libfdt installed to get rid of a few ifdefs in the code. Warning: This patch will likely make configure fail for people who don't select their own --target-list, but don't have libfdt development packages installed. However, we really need this new dependency to move on. Signed-off-by: Alexander Graf --- v1 -> v2: - no paranthesis - no fdt check for config_pseries - add . in error message --- configure | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/configure b/configure index f8dd4db6c5..18537e8404 100755 --- a/configure +++ b/configure @@ -3422,7 +3422,16 @@ case "$target_arch2" in fi fi esac -if test "$target_arch2" = "ppc64" -a "$fdt" = "yes"; then +if test "$fdt" != "yes" && test "$target_arch2" = "ppc" -o \ + "$target_arch2" = "ppc64" -o "$target_arch2" = "ppcemb"; then + echo + echo "Error: libfdt missing" + echo "The PowerPC target requires libfdt to work properly." + echo "Please make sure to have it and its development packages installed." + echo + exit 1 +fi +if test "$target_arch2" = "ppc64"; then echo "CONFIG_PSERIES=y" >> $config_target_mak fi if test "$target_bigendian" = "yes" ; then From a7342588c081c7497bc7810431a03fa7b669af40 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 17 Oct 2011 18:15:41 +0000 Subject: [PATCH 19/25] pseries: Correct vmx/dfp handling in both KVM and TCG cases Currently, when KVM is enabled, the pseries machine checks if the host CPU supports VMX, VSX and/or DFP instructions and advertises accordingly in the guest device tree. It does this regardless of what CPU is selected on the command line. On the other hand, when in TCG mode, it never advertises any of these facilities, even basic VMX (Altivec) which is supported in TCG. Now that we have a -cpu host option for ppc, it is fairly straightforward to fix both problems. This patch changes the -cpu host code to override the basic cpu spec derived from the PVR with information queried from the host avout VMX, VSX and DFP capability. The pseries code then uses the instruction availability advertised in the cpu state to set the guest device tree correctly for both the KVM and TCG cases. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr.c | 10 +++++----- target-ppc/cpu.h | 20 ++++++++++++++++++++ target-ppc/kvm.c | 23 ++++++++++++++++++++++- target-ppc/translate_init.c | 18 ++---------------- 4 files changed, 49 insertions(+), 22 deletions(-) diff --git a/hw/spapr.c b/hw/spapr.c index 08c7399fef..933af322c5 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -188,8 +188,6 @@ static void *spapr_create_fdt_skel(const char *cpu_model, 0xffffffff, 0xffffffff}; uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq() : TIMEBASE_FREQ; uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000; - uint32_t vmx = kvm_enabled() ? kvmppc_get_vmx() : 0; - uint32_t dfp = kvm_enabled() ? kvmppc_get_dfp() : 0; if ((index % smt) != 0) { continue; @@ -241,15 +239,17 @@ static void *spapr_create_fdt_skel(const char *cpu_model, * 0 / no property == no vector extensions * 1 == VMX / Altivec available * 2 == VSX available */ - if (vmx) { + if (env->insns_flags & PPC_ALTIVEC) { + uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1; + _FDT((fdt_property_cell(fdt, "ibm,vmx", vmx))); } /* Advertise DFP (Decimal Floating Point) if available * 0 / no property == no DFP * 1 == DFP available */ - if (dfp) { - _FDT((fdt_property_cell(fdt, "ibm,dfp", dfp))); + if (env->insns_flags2 & PPC2_DFP) { + _FDT((fdt_property_cell(fdt, "ibm,dfp", 1))); } _FDT((fdt_end_node(fdt))); diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index f36f375596..3ef4eba836 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -858,6 +858,22 @@ enum { /* The whole PowerPC CPU context */ #define NB_MMU_MODES 3 +struct ppc_def_t { + const char *name; + uint32_t pvr; + uint32_t svr; + uint64_t insns_flags; + uint64_t insns_flags2; + uint64_t msr_mask; + powerpc_mmu_t mmu_model; + powerpc_excp_t excp_model; + powerpc_input_t bus_model; + uint32_t flags; + int bfd_mach; + void (*init_proc)(CPUPPCState *env); + int (*check_pow)(CPUPPCState *env); +}; + struct CPUPPCState { /* First are the most commonly used resources * during translated code execution @@ -1844,6 +1860,10 @@ enum { /* BookE 2.06 PowerPC specification */ PPC2_BOOKE206 = 0x0000000000000001ULL, + /* VSX (extensions to Altivec / VMX) */ + PPC2_VSX = 0x0000000000000002ULL, + /* Decimal Floating Point (DFP) */ + PPC2_DFP = 0x0000000000000004ULL, }; /*****************************************************************************/ diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 313c7b2af2..a090d79ad4 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -888,14 +888,35 @@ static inline uint32_t mfpvr(void) return pvr; } +static void alter_insns(uint64_t *word, uint64_t flags, bool on) +{ + if (on) { + *word |= flags; + } else { + *word &= ~flags; + } +} + const ppc_def_t *kvmppc_host_cpu_def(void) { uint32_t host_pvr = mfpvr(); const ppc_def_t *base_spec; + ppc_def_t *spec; + uint32_t vmx = kvmppc_get_vmx(); + uint32_t dfp = kvmppc_get_dfp(); base_spec = ppc_find_by_pvr(host_pvr); - return base_spec; + spec = g_malloc0(sizeof(*spec)); + memcpy(spec, base_spec, sizeof(*spec)); + + /* Now fix up the spec with information we can query from the host */ + + alter_insns(&spec->insns_flags, PPC_ALTIVEC, vmx > 0); + alter_insns(&spec->insns_flags2, PPC2_VSX, vmx > 1); + alter_insns(&spec->insns_flags2, PPC2_DFP, dfp); + + return spec; } bool kvm_arch_stop_on_emulation_error(CPUState *env) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index f0ae1d1764..4dfd7f3bfb 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -34,22 +34,6 @@ #define TODO_USER_ONLY 1 #endif -struct ppc_def_t { - const char *name; - uint32_t pvr; - uint32_t svr; - uint64_t insns_flags; - uint64_t insns_flags2; - uint64_t msr_mask; - powerpc_mmu_t mmu_model; - powerpc_excp_t excp_model; - powerpc_input_t bus_model; - uint32_t flags; - int bfd_mach; - void (*init_proc)(CPUPPCState *env); - int (*check_pow)(CPUPPCState *env); -}; - /* For user-mode emulation, we don't emulate any IRQ controller */ #if defined(CONFIG_USER_ONLY) #define PPC_IRQ_INIT_FN(name) \ @@ -6535,6 +6519,8 @@ static void init_proc_970MP (CPUPPCState *env) PPC_64B | PPC_ALTIVEC | \ PPC_SEGMENT_64B | PPC_SLBI | \ PPC_POPCNTB | PPC_POPCNTWD) +/* FIXME: Should also have PPC2_VSX and PPC2_DFP, but we don't + * implement those in TCG yet */ #define POWERPC_INSNS2_POWER7 (PPC_NONE) #define POWERPC_MSRM_POWER7 (0x800000000204FF36ULL) #define POWERPC_MMU_POWER7 (POWERPC_MMU_2_06) From 98efaf75282a96ffbe2914f79a9f5cb736a03db4 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Sun, 23 Oct 2011 17:25:04 +0000 Subject: [PATCH 20/25] ppc: Fix up usermode only builds The recent usage of MemoryRegion in kvm_ppc.h breaks builds with CONFIG_USER_ONLY=y. This patch fixes it. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/kvm_ppc.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index b0d6fb667e..f9c0198311 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -23,9 +23,11 @@ int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len); int kvmppc_set_interrupt(CPUState *env, int irq, int level); void kvmppc_set_papr(CPUState *env); int kvmppc_smt_threads(void); +#ifndef CONFIG_USER_ONLY off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem); void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd); int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size); +#endif /* !CONFIG_USER_ONLY */ const ppc_def_t *kvmppc_host_cpu_def(void); #else @@ -69,6 +71,7 @@ static inline int kvmppc_smt_threads(void) return 1; } +#ifndef CONFIG_USER_ONLY static inline off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem) { return 0; @@ -85,6 +88,7 @@ static inline int kvmppc_remove_spapr_tce(void *table, int pfd, { return -1; } +#endif /* !CONFIG_USER_ONLY */ static inline const ppc_def_t *kvmppc_host_cpu_def(void) { From 70bca53ffb811ea59dc090b3ca7825cf0bf346a7 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 24 Oct 2011 20:43:22 +0200 Subject: [PATCH 21/25] KVM: PPC: Override host vmx/vsx/dfp only when information known The -cpu host feature tries to find out the host capabilities based on device tree information. However, we don't always have that available because it's an optional property in dt. So instead of force unsetting values depending on an unreliable source of information, let's just try to be clever about it and not override capabilities when we don't know the device tree pieces. This fixes altivec with -cpu host on YDL PowerStations. Reported-by: Nishanth Aravamudan Acked-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/kvm.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index a090d79ad4..f3d0861a11 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -912,9 +912,15 @@ const ppc_def_t *kvmppc_host_cpu_def(void) /* Now fix up the spec with information we can query from the host */ - alter_insns(&spec->insns_flags, PPC_ALTIVEC, vmx > 0); - alter_insns(&spec->insns_flags2, PPC2_VSX, vmx > 1); - alter_insns(&spec->insns_flags2, PPC2_DFP, dfp); + if (vmx != -1) { + /* Only override when we know what the host supports */ + alter_insns(&spec->insns_flags, PPC_ALTIVEC, vmx > 0); + alter_insns(&spec->insns_flags2, PPC2_VSX, vmx > 1); + } + if (dfp != -1) { + /* Only override when we know what the host supports */ + alter_insns(&spec->insns_flags2, PPC2_DFP, dfp); + } return spec; } From 74b41e5676568e6560474267bbf1a5a32d3e2c41 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 27 Oct 2011 15:56:31 +0000 Subject: [PATCH 22/25] pseries: Allow writes to KVM accelerated TCE table Sufficiently recent kernels include a KVM call to accelerate use of PAPR TCE tables (IOMMU), which are used by PAPR virtual IO devices. This involves qemu mapping the TCE table in from a kernel obtained fd, which currently we do with PROT_READ only. This is a hangover from early (never released) versions of this kernel interface which only permitted read-only mappings and required us to destroy and recreate the table when we needed to clear it from qemu. Now, the kernel permits read-write mappings, and we rely on this to clear the table in spapr_vio_quiesce_one(). However, due to insufficient testing, I forgot to update the actual mapping of the table in kvmppc_create_spapr_tce() to add PROT_WRITE to the mmap(). This patch corrects the oversight. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/kvm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index f3d0861a11..429349fb94 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -850,7 +850,7 @@ void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd) len = (window_size / SPAPR_VIO_TCE_PAGE_SIZE) * sizeof(VIOsPAPR_RTCE); /* FIXME: round this up to page size */ - table = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0); + table = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (table == MAP_FAILED) { close(fd); return NULL; From 02d4eae4b0be19d84996105cf6e0cc33f41e3833 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Sun, 30 Oct 2011 15:51:24 +0000 Subject: [PATCH 23/25] ppc: Alter CPU state to mask out TCG unimplemented instructions as appropriate The CPU state contains two bitmaps, initialized from the CPU spec which describes which instructions are implemented on the CPU. A couple of bits are defined which cover instructions (VSX and DFP) which are not currently implemented in TCG. So far, these are only used to handle the case of -cpu host because a KVM guest can use the instructions when the host CPU supports them. However, it's a mild layering violation to simply not include those bits in the CPU descriptions for those CPUs that do support them, just because we can't handle them in TCG. This patch corrects the situation, so that the instruction bits _are_ shown correctly in the cpu spec table, but are masked out from the cpu state in the non-KVM case. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/cpu.h | 26 ++++++++++++++++++++++++++ target-ppc/translate_init.c | 20 +++++++++++++++++--- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 3ef4eba836..e84108c49a 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1856,6 +1856,30 @@ enum { /* popcntw and popcntd instructions */ PPC_POPCNTWD = 0x8000000000000000ULL, +#define PPC_TCG_INSNS (PPC_INSNS_BASE | PPC_POWER | PPC_POWER2 \ + | PPC_POWER_RTC | PPC_POWER_BR | PPC_64B \ + | PPC_64BX | PPC_64H | PPC_WAIT | PPC_MFTB \ + | PPC_602_SPEC | PPC_ISEL | PPC_POPCNTB \ + | PPC_STRING | PPC_FLOAT | PPC_FLOAT_EXT \ + | PPC_FLOAT_FSQRT | PPC_FLOAT_FRES \ + | PPC_FLOAT_FRSQRTE | PPC_FLOAT_FRSQRTES \ + | PPC_FLOAT_FSEL | PPC_FLOAT_STFIWX \ + | PPC_ALTIVEC | PPC_SPE | PPC_SPE_SINGLE \ + | PPC_SPE_DOUBLE | PPC_MEM_TLBIA \ + | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC \ + | PPC_MEM_SYNC | PPC_MEM_EIEIO \ + | PPC_CACHE | PPC_CACHE_ICBI \ + | PPC_CACHE_DCBZ | PPC_CACHE_DCBZT \ + | PPC_CACHE_DCBA | PPC_CACHE_LOCK \ + | PPC_EXTERN | PPC_SEGMENT | PPC_6xx_TLB \ + | PPC_74xx_TLB | PPC_40x_TLB | PPC_SEGMENT_64B \ + | PPC_SLBI | PPC_WRTEE | PPC_40x_EXCP \ + | PPC_405_MAC | PPC_440_SPEC | PPC_BOOKE \ + | PPC_MFAPIDI | PPC_TLBIVA | PPC_TLBIVAX \ + | PPC_4xx_COMMON | PPC_40x_ICBT | PPC_RFMCI \ + | PPC_RFDI | PPC_DCR | PPC_DCRX | PPC_DCRUX \ + | PPC_POPCNTWD) + /* extended type values */ /* BookE 2.06 PowerPC specification */ @@ -1864,6 +1888,8 @@ enum { PPC2_VSX = 0x0000000000000002ULL, /* Decimal Floating Point (DFP) */ PPC2_DFP = 0x0000000000000004ULL, + +#define PPC_TCG_INSNS2 (PPC2_BOOKE206) }; /*****************************************************************************/ diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 4dfd7f3bfb..8a7233fc82 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -6519,9 +6519,7 @@ static void init_proc_970MP (CPUPPCState *env) PPC_64B | PPC_ALTIVEC | \ PPC_SEGMENT_64B | PPC_SLBI | \ PPC_POPCNTB | PPC_POPCNTWD) -/* FIXME: Should also have PPC2_VSX and PPC2_DFP, but we don't - * implement those in TCG yet */ -#define POWERPC_INSNS2_POWER7 (PPC_NONE) +#define POWERPC_INSNS2_POWER7 (PPC2_VSX | PPC2_DFP) #define POWERPC_MSRM_POWER7 (0x800000000204FF36ULL) #define POWERPC_MMU_POWER7 (POWERPC_MMU_2_06) #define POWERPC_EXCP_POWER7 (POWERPC_EXCP_POWER7) @@ -9848,6 +9846,22 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def) env->bus_model = def->bus_model; env->insns_flags = def->insns_flags; env->insns_flags2 = def->insns_flags2; + if (!kvm_enabled()) { + /* TCG doesn't (yet) emulate some groups of instructions that + * are implemented on some otherwise supported CPUs (e.g. VSX + * and decimal floating point instructions on POWER7). We + * remove unsupported instruction groups from the cpu state's + * instruction masks and hope the guest can cope. For at + * least the pseries machine, the unavailability of these + * instructions can be advertise to the guest via the device + * tree. + * + * FIXME: we should have a similar masking for CPU features + * not accessible under KVM, but so far, there aren't any of + * those. */ + env->insns_flags &= PPC_TCG_INSNS; + env->insns_flags2 &= PPC_TCG_INSNS2; + } env->flags = def->flags; env->bfd_mach = def->bfd_mach; env->check_pow = def->check_pow; From 3384f95c59e5db381cf3e605c8acec71baf0e6b8 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Sun, 30 Oct 2011 17:16:46 +0000 Subject: [PATCH 24/25] pseries: Add partial support for PCI This patch adds a PCI bus to the pseries machine. This instantiates the qemu generic PCI bus code, advertises a PCI host bridge in the guest's device tree and implements the RTAS methods specified by PAPR to access PCI config space. It also sets up the memory regions we need to provide windows into the PCI memory and IO space, and advertises those to the guest. However, because qemu can't yet emulate an IOMMU, which is mandatory on pseries, PCI devices which use DMA (i.e. most of them) will not work with this code alone. Still, this is enough to support the virtio_pci device (which probably _should_ use emulated PCI DMA, but is specced to use direct hypervisor access to guest physical memory instead). [agraf] remove typedef which could cause compile errors Signed-off-by: Alexey Kardashevskiy Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- Makefile.target | 1 + hw/spapr.c | 36 +++- hw/spapr.h | 2 + hw/spapr_pci.c | 508 ++++++++++++++++++++++++++++++++++++++++++++++++ hw/spapr_pci.h | 61 ++++++ 5 files changed, 604 insertions(+), 4 deletions(-) create mode 100644 hw/spapr_pci.c create mode 100644 hw/spapr_pci.h diff --git a/Makefile.target b/Makefile.target index fe5f6f70af..2329df50a5 100644 --- a/Makefile.target +++ b/Makefile.target @@ -248,6 +248,7 @@ obj-ppc-y += ppc_newworld.o # IBM pSeries (sPAPR) obj-ppc-$(CONFIG_PSERIES) += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o obj-ppc-$(CONFIG_PSERIES) += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o +obj-ppc-$(CONFIG_PSERIES) += spapr_pci.o device-hotplug.o pci-hotplug.o # PowerPC 4xx boards obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o obj-ppc-y += ppc440.o ppc440_bamboo.o diff --git a/hw/spapr.c b/hw/spapr.c index 933af322c5..bdaa938b6b 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -39,10 +39,12 @@ #include "hw/spapr.h" #include "hw/spapr_vio.h" +#include "hw/spapr_pci.h" #include "hw/xics.h" #include "kvm.h" #include "kvm_ppc.h" +#include "pci.h" #include "exec-memory.h" @@ -62,6 +64,11 @@ #define MAX_CPUS 256 #define XICS_IRQS 1024 +#define SPAPR_PCI_BUID 0x800000020000001ULL +#define SPAPR_PCI_MEM_WIN_ADDR (0x10000000000ULL + 0xA0000000) +#define SPAPR_PCI_MEM_WIN_SIZE 0x20000000 +#define SPAPR_PCI_IO_WIN_ADDR (0x10000000000ULL + 0x80000000) + #define PHANDLE_XICP 0x00001111 sPAPREnvironment *spapr; @@ -146,6 +153,14 @@ static void *spapr_create_fdt_skel(const char *cpu_model, &end_prop, sizeof(end_prop)))); _FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device))); + /* + * Because we don't always invoke any firmware, we can't rely on + * that to do BAR allocation. Long term, we should probably do + * that ourselves, but for now, this setting (plus advertising the + * current BARs as 0) causes sufficiently recent kernels to to the + * BAR assignment themselves */ + _FDT((fdt_property_cell(fdt, "linux,pci-probe-only", 0))); + _FDT((fdt_end_node(fdt))); /* memory node(s) */ @@ -308,6 +323,7 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr, { int ret; void *fdt; + sPAPRPHBState *phb; fdt = g_malloc(FDT_MAX_SIZE); @@ -320,6 +336,15 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr, exit(1); } + QLIST_FOREACH(phb, &spapr->phbs, list) { + ret = spapr_populate_pci_devices(phb, PHANDLE_XICP, fdt); + } + + if (ret < 0) { + fprintf(stderr, "couldn't setup PCI devices in fdt\n"); + exit(1); + } + /* RTAS */ ret = spapr_rtas_device_tree_setup(fdt, rtas_addr, rtas_size); if (ret < 0) { @@ -478,6 +503,12 @@ static void ppc_spapr_init(ram_addr_t ram_size, } } + /* Set up PCI */ + spapr_create_phb(spapr, "pci", SPAPR_PCI_BUID, + SPAPR_PCI_MEM_WIN_ADDR, + SPAPR_PCI_MEM_WIN_SIZE, + SPAPR_PCI_IO_WIN_ADDR); + for (i = 0; i < nb_nics; i++) { NICInfo *nd = &nd_table[i]; @@ -488,10 +519,7 @@ static void ppc_spapr_init(ram_addr_t ram_size, if (strcmp(nd->model, "ibmveth") == 0) { spapr_vlan_create(spapr->vio_bus, 0x1000 + i, nd); } else { - fprintf(stderr, "pSeries (sPAPR) platform does not support " - "NIC model '%s' (only ibmveth is supported)\n", - nd->model); - exit(1); + pci_nic_init_nofail(&nd_table[i], nd->model, NULL); } } diff --git a/hw/spapr.h b/hw/spapr.h index 6657c336f6..df88f6abad 100644 --- a/hw/spapr.h +++ b/hw/spapr.h @@ -4,10 +4,12 @@ #include "hw/xics.h" struct VIOsPAPRBus; +struct sPAPRPHBState; struct icp_state; typedef struct sPAPREnvironment { struct VIOsPAPRBus *vio_bus; + QLIST_HEAD(, sPAPRPHBState) phbs; struct icp_state *icp; target_phys_addr_t ram_limit; diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c new file mode 100644 index 0000000000..2a5e6374c3 --- /dev/null +++ b/hw/spapr_pci.c @@ -0,0 +1,508 @@ +/* + * QEMU sPAPR PCI host originated from Uninorth PCI host + * + * Copyright (c) 2011 Alexey Kardashevskiy, IBM Corporation. + * Copyright (C) 2011 David Gibson, IBM Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "hw.h" +#include "pci.h" +#include "pci_host.h" +#include "hw/spapr.h" +#include "hw/spapr_pci.h" +#include "exec-memory.h" +#include + +#include "hw/pci_internals.h" + +static const uint32_t bars[] = { + PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, + PCI_BASE_ADDRESS_2, PCI_BASE_ADDRESS_3, + PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5 + /*, PCI_ROM_ADDRESS*/ +}; + +static PCIDevice *find_dev(sPAPREnvironment *spapr, + uint64_t buid, uint32_t config_addr) +{ + DeviceState *qdev; + int devfn = (config_addr >> 8) & 0xFF; + sPAPRPHBState *phb; + + QLIST_FOREACH(phb, &spapr->phbs, list) { + if (phb->buid != buid) { + continue; + } + + QLIST_FOREACH(qdev, &phb->host_state.bus->qbus.children, sibling) { + PCIDevice *dev = (PCIDevice *)qdev; + if (dev->devfn == devfn) { + return dev; + } + } + } + + return NULL; +} + +static void rtas_ibm_read_pci_config(sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, + target_ulong args, + uint32_t nret, target_ulong rets) +{ + uint32_t val, size, addr; + uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2); + PCIDevice *dev = find_dev(spapr, buid, rtas_ld(args, 0)); + + if (!dev) { + rtas_st(rets, 0, -1); + return; + } + size = rtas_ld(args, 3); + addr = rtas_ld(args, 0) & 0xFF; + val = pci_default_read_config(dev, addr, size); + rtas_st(rets, 0, 0); + rtas_st(rets, 1, val); +} + +static void rtas_read_pci_config(sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, + target_ulong args, + uint32_t nret, target_ulong rets) +{ + uint32_t val, size, addr; + PCIDevice *dev = find_dev(spapr, 0, rtas_ld(args, 0)); + + if (!dev) { + rtas_st(rets, 0, -1); + return; + } + size = rtas_ld(args, 1); + addr = rtas_ld(args, 0) & 0xFF; + val = pci_default_read_config(dev, addr, size); + rtas_st(rets, 0, 0); + rtas_st(rets, 1, val); +} + +static void rtas_ibm_write_pci_config(sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, + target_ulong args, + uint32_t nret, target_ulong rets) +{ + uint32_t val, size, addr; + uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2); + PCIDevice *dev = find_dev(spapr, buid, rtas_ld(args, 0)); + + if (!dev) { + rtas_st(rets, 0, -1); + return; + } + val = rtas_ld(args, 4); + size = rtas_ld(args, 3); + addr = rtas_ld(args, 0) & 0xFF; + pci_default_write_config(dev, addr, val, size); + rtas_st(rets, 0, 0); +} + +static void rtas_write_pci_config(sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, + target_ulong args, + uint32_t nret, target_ulong rets) +{ + uint32_t val, size, addr; + PCIDevice *dev = find_dev(spapr, 0, rtas_ld(args, 0)); + + if (!dev) { + rtas_st(rets, 0, -1); + return; + } + val = rtas_ld(args, 2); + size = rtas_ld(args, 1); + addr = rtas_ld(args, 0) & 0xFF; + pci_default_write_config(dev, addr, val, size); + rtas_st(rets, 0, 0); +} + +static int pci_spapr_map_irq(PCIDevice *pci_dev, int irq_num) +{ + /* + * Here we need to convert pci_dev + irq_num to some unique value + * which is less than number of IRQs on the specific bus (now it + * is 16). At the moment irq_num == device_id (number of the + * slot?) + * FIXME: we should swizzle in fn and irq_num + */ + return (pci_dev->devfn >> 3) % SPAPR_PCI_NUM_LSI; +} + +static void pci_spapr_set_irq(void *opaque, int irq_num, int level) +{ + /* + * Here we use the number returned by pci_spapr_map_irq to find a + * corresponding qemu_irq. + */ + sPAPRPHBState *phb = opaque; + + qemu_set_irq(phb->lsi_table[irq_num].qirq, level); +} + +static int spapr_phb_init(SysBusDevice *s) +{ + sPAPRPHBState *phb = FROM_SYSBUS(sPAPRPHBState, s); + int i; + + /* Initialize the LSI table */ + for (i = 0; i < SPAPR_PCI_NUM_LSI; i++) { + qemu_irq qirq; + uint32_t num; + + qirq = spapr_allocate_irq(0, &num); + if (!qirq) { + return -1; + } + + phb->lsi_table[i].dt_irq = num; + phb->lsi_table[i].qirq = qirq; + } + + return 0; +} + +static int spapr_main_pci_host_init(PCIDevice *d) +{ + return 0; +} + +static PCIDeviceInfo spapr_main_pci_host_info = { + .qdev.name = "spapr-pci-host-bridge", + .qdev.size = sizeof(PCIDevice), + .init = spapr_main_pci_host_init, +}; + +static void spapr_register_devices(void) +{ + sysbus_register_dev("spapr-pci-host-bridge", sizeof(sPAPRPHBState), + spapr_phb_init); + pci_qdev_register(&spapr_main_pci_host_info); +} + +device_init(spapr_register_devices) + +static uint64_t spapr_io_read(void *opaque, target_phys_addr_t addr, + unsigned size) +{ + switch (size) { + case 1: + return cpu_inb(addr); + case 2: + return cpu_inw(addr); + case 4: + return cpu_inl(addr); + } + assert(0); +} + +static void spapr_io_write(void *opaque, target_phys_addr_t addr, + uint64_t data, unsigned size) +{ + switch (size) { + case 1: + cpu_outb(addr, data); + return; + case 2: + cpu_outw(addr, data); + return; + case 4: + cpu_outl(addr, data); + return; + } + assert(0); +} + +static MemoryRegionOps spapr_io_ops = { + .endianness = DEVICE_LITTLE_ENDIAN, + .read = spapr_io_read, + .write = spapr_io_write +}; + +void spapr_create_phb(sPAPREnvironment *spapr, + const char *busname, uint64_t buid, + uint64_t mem_win_addr, uint64_t mem_win_size, + uint64_t io_win_addr) +{ + DeviceState *dev; + SysBusDevice *s; + sPAPRPHBState *phb; + PCIBus *bus; + char namebuf[strlen(busname)+11]; + + dev = qdev_create(NULL, "spapr-pci-host-bridge"); + qdev_init_nofail(dev); + s = sysbus_from_qdev(dev); + phb = FROM_SYSBUS(sPAPRPHBState, s); + + phb->mem_win_addr = mem_win_addr; + + sprintf(namebuf, "%s-mem", busname); + memory_region_init(&phb->memspace, namebuf, INT64_MAX); + + sprintf(namebuf, "%s-memwindow", busname); + memory_region_init_alias(&phb->memwindow, namebuf, &phb->memspace, + SPAPR_PCI_MEM_WIN_BUS_OFFSET, mem_win_size); + memory_region_add_subregion(get_system_memory(), mem_win_addr, + &phb->memwindow); + + phb->io_win_addr = io_win_addr; + + /* On ppc, we only have MMIO no specific IO space from the CPU + * perspective. In theory we ought to be able to embed the PCI IO + * memory region direction in the system memory space. However, + * if any of the IO BAR subregions use the old_portio mechanism, + * that won't be processed properly unless accessed from the + * system io address space. This hack to bounce things via + * system_io works around the problem until all the users of + * old_portion are updated */ + sprintf(namebuf, "%s-io", busname); + memory_region_init(&phb->iospace, namebuf, SPAPR_PCI_IO_WIN_SIZE); + /* FIXME: fix to support multiple PHBs */ + memory_region_add_subregion(get_system_io(), 0, &phb->iospace); + + sprintf(namebuf, "%s-iowindow", busname); + memory_region_init_io(&phb->iowindow, &spapr_io_ops, phb, + namebuf, SPAPR_PCI_IO_WIN_SIZE); + memory_region_add_subregion(get_system_memory(), io_win_addr, + &phb->iowindow); + + phb->host_state.bus = bus = pci_register_bus(&phb->busdev.qdev, busname, + pci_spapr_set_irq, + pci_spapr_map_irq, + phb, + &phb->memspace, &phb->iospace, + PCI_DEVFN(0, 0), + SPAPR_PCI_NUM_LSI); + + spapr_rtas_register("read-pci-config", rtas_read_pci_config); + spapr_rtas_register("write-pci-config", rtas_write_pci_config); + spapr_rtas_register("ibm,read-pci-config", rtas_ibm_read_pci_config); + spapr_rtas_register("ibm,write-pci-config", rtas_ibm_write_pci_config); + + QLIST_INSERT_HEAD(&spapr->phbs, phb, list); + + /* pci_bus_set_mem_base(bus, mem_va_start - SPAPR_PCI_MEM_BAR_START); */ +} + +/* Macros to operate with address in OF binding to PCI */ +#define b_x(x, p, l) (((x) & ((1<<(l))-1)) << (p)) +#define b_n(x) b_x((x), 31, 1) /* 0 if relocatable */ +#define b_p(x) b_x((x), 30, 1) /* 1 if prefetchable */ +#define b_t(x) b_x((x), 29, 1) /* 1 if the address is aliased */ +#define b_ss(x) b_x((x), 24, 2) /* the space code */ +#define b_bbbbbbbb(x) b_x((x), 16, 8) /* bus number */ +#define b_ddddd(x) b_x((x), 11, 5) /* device number */ +#define b_fff(x) b_x((x), 8, 3) /* function number */ +#define b_rrrrrrrr(x) b_x((x), 0, 8) /* register number */ + +static uint32_t regtype_to_ss(uint8_t type) +{ + if (type & PCI_BASE_ADDRESS_MEM_TYPE_64) { + return 3; + } + if (type == PCI_BASE_ADDRESS_SPACE_IO) { + return 1; + } + return 2; +} + +int spapr_populate_pci_devices(sPAPRPHBState *phb, + uint32_t xics_phandle, + void *fdt) +{ + PCIBus *bus = phb->host_state.bus; + int bus_off, node_off = 0, devid, fn, i, n, devices; + DeviceState *qdev; + char nodename[256]; + struct { + uint32_t hi; + uint64_t addr; + uint64_t size; + } __attribute__((packed)) reg[PCI_NUM_REGIONS + 1], + assigned_addresses[PCI_NUM_REGIONS]; + uint32_t bus_range[] = { cpu_to_be32(0), cpu_to_be32(0xff) }; + struct { + uint32_t hi; + uint64_t child; + uint64_t parent; + uint64_t size; + } __attribute__((packed)) ranges[] = { + { + cpu_to_be32(b_ss(1)), cpu_to_be64(0), + cpu_to_be64(phb->io_win_addr), + cpu_to_be64(memory_region_size(&phb->iospace)), + }, + { + cpu_to_be32(b_ss(2)), cpu_to_be64(SPAPR_PCI_MEM_WIN_BUS_OFFSET), + cpu_to_be64(phb->mem_win_addr), + cpu_to_be64(memory_region_size(&phb->memwindow)), + }, + }; + uint64_t bus_reg[] = { cpu_to_be64(phb->buid), 0 }; + uint32_t interrupt_map_mask[] = { + cpu_to_be32(b_ddddd(-1)|b_fff(-1)), 0x0, 0x0, 0x0}; + uint32_t interrupt_map[bus->nirq][7]; + + /* Start populating the FDT */ + sprintf(nodename, "pci@%" PRIx64, phb->buid); + bus_off = fdt_add_subnode(fdt, 0, nodename); + if (bus_off < 0) { + return bus_off; + } + +#define _FDT(exp) \ + do { \ + int ret = (exp); \ + if (ret < 0) { \ + return ret; \ + } \ + } while (0) + + /* Write PHB properties */ + _FDT(fdt_setprop_string(fdt, bus_off, "device_type", "pci")); + _FDT(fdt_setprop_string(fdt, bus_off, "compatible", "IBM,Logical_PHB")); + _FDT(fdt_setprop_cell(fdt, bus_off, "#address-cells", 0x3)); + _FDT(fdt_setprop_cell(fdt, bus_off, "#size-cells", 0x2)); + _FDT(fdt_setprop_cell(fdt, bus_off, "#interrupt-cells", 0x1)); + _FDT(fdt_setprop(fdt, bus_off, "used-by-rtas", NULL, 0)); + _FDT(fdt_setprop(fdt, bus_off, "bus-range", &bus_range, sizeof(bus_range))); + _FDT(fdt_setprop(fdt, bus_off, "ranges", &ranges, sizeof(ranges))); + _FDT(fdt_setprop(fdt, bus_off, "reg", &bus_reg, sizeof(bus_reg))); + _FDT(fdt_setprop(fdt, bus_off, "interrupt-map-mask", + &interrupt_map_mask, sizeof(interrupt_map_mask))); + + /* Populate PCI devices and allocate IRQs */ + devices = 0; + QLIST_FOREACH(qdev, &bus->qbus.children, sibling) { + PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev); + int irq_index = pci_spapr_map_irq(dev, 0); + uint32_t *irqmap = interrupt_map[devices]; + uint8_t *config = dev->config; + + devid = dev->devfn >> 3; + fn = dev->devfn & 7; + + sprintf(nodename, "pci@%u,%u", devid, fn); + + /* Allocate interrupt from the map */ + if (devid > bus->nirq) { + printf("Unexpected behaviour in spapr_populate_pci_devices," + "wrong devid %u\n", devid); + exit(-1); + } + irqmap[0] = cpu_to_be32(b_ddddd(devid)|b_fff(fn)); + irqmap[1] = 0; + irqmap[2] = 0; + irqmap[3] = 0; + irqmap[4] = cpu_to_be32(xics_phandle); + irqmap[5] = cpu_to_be32(phb->lsi_table[irq_index].dt_irq); + irqmap[6] = cpu_to_be32(0x8); + + /* Add node to FDT */ + node_off = fdt_add_subnode(fdt, bus_off, nodename); + if (node_off < 0) { + return node_off; + } + + _FDT(fdt_setprop_cell(fdt, node_off, "vendor-id", + pci_get_word(&config[PCI_VENDOR_ID]))); + _FDT(fdt_setprop_cell(fdt, node_off, "device-id", + pci_get_word(&config[PCI_DEVICE_ID]))); + _FDT(fdt_setprop_cell(fdt, node_off, "revision-id", + pci_get_byte(&config[PCI_REVISION_ID]))); + _FDT(fdt_setprop_cell(fdt, node_off, "class-code", + pci_get_long(&config[PCI_CLASS_REVISION]) >> 8)); + _FDT(fdt_setprop_cell(fdt, node_off, "subsystem-id", + pci_get_word(&config[PCI_SUBSYSTEM_ID]))); + _FDT(fdt_setprop_cell(fdt, node_off, "subsystem-vendor-id", + pci_get_word(&config[PCI_SUBSYSTEM_VENDOR_ID]))); + + /* Config space region comes first */ + reg[0].hi = cpu_to_be32( + b_n(0) | + b_p(0) | + b_t(0) | + b_ss(0/*config*/) | + b_bbbbbbbb(0) | + b_ddddd(devid) | + b_fff(fn)); + reg[0].addr = 0; + reg[0].size = 0; + + n = 0; + for (i = 0; i < PCI_NUM_REGIONS; ++i) { + if (0 == dev->io_regions[i].size) { + continue; + } + + reg[n+1].hi = cpu_to_be32( + b_n(0) | + b_p(0) | + b_t(0) | + b_ss(regtype_to_ss(dev->io_regions[i].type)) | + b_bbbbbbbb(0) | + b_ddddd(devid) | + b_fff(fn) | + b_rrrrrrrr(bars[i])); + reg[n+1].addr = 0; + reg[n+1].size = cpu_to_be64(dev->io_regions[i].size); + + assigned_addresses[n].hi = cpu_to_be32( + b_n(1) | + b_p(0) | + b_t(0) | + b_ss(regtype_to_ss(dev->io_regions[i].type)) | + b_bbbbbbbb(0) | + b_ddddd(devid) | + b_fff(fn) | + b_rrrrrrrr(bars[i])); + + /* + * Writing zeroes to assigned_addresses causes the guest kernel to + * reassign BARs + */ + assigned_addresses[n].addr = cpu_to_be64(dev->io_regions[i].addr); + assigned_addresses[n].size = reg[n+1].size; + + ++n; + } + _FDT(fdt_setprop(fdt, node_off, "reg", reg, sizeof(reg[0])*(n+1))); + _FDT(fdt_setprop(fdt, node_off, "assigned-addresses", + assigned_addresses, + sizeof(assigned_addresses[0])*(n))); + _FDT(fdt_setprop_cell(fdt, node_off, "interrupts", + pci_get_byte(&config[PCI_INTERRUPT_PIN]))); + + ++devices; + } + + /* Write interrupt map */ + _FDT(fdt_setprop(fdt, bus_off, "interrupt-map", &interrupt_map, + devices * sizeof(interrupt_map[0]))); + + return 0; +} diff --git a/hw/spapr_pci.h b/hw/spapr_pci.h new file mode 100644 index 0000000000..213340c915 --- /dev/null +++ b/hw/spapr_pci.h @@ -0,0 +1,61 @@ +/* + * QEMU SPAPR PCI BUS definitions + * + * Copyright (c) 2011 Alexey Kardashevskiy + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#if !defined(__HW_SPAPR_H__) +#error Please include spapr.h before this file! +#endif + +#if !defined(__HW_SPAPR_PCI_H__) +#define __HW_SPAPR_PCI_H__ + +#include "hw/pci_host.h" +#include "hw/xics.h" + +#define SPAPR_PCI_NUM_LSI 16 + +typedef struct sPAPRPHBState { + SysBusDevice busdev; + PCIHostState host_state; + + uint64_t buid; + + MemoryRegion memspace, iospace; + target_phys_addr_t mem_win_addr, io_win_addr; + MemoryRegion memwindow, iowindow; + + struct { + uint32_t dt_irq; + qemu_irq qirq; + } lsi_table[SPAPR_PCI_NUM_LSI]; + + QLIST_ENTRY(sPAPRPHBState) list; +} sPAPRPHBState; + +#define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL +#define SPAPR_PCI_IO_WIN_SIZE 0x10000 + +void spapr_create_phb(sPAPREnvironment *spapr, + const char *busname, uint64_t buid, + uint64_t mem_win_addr, uint64_t mem_win_size, + uint64_t io_win_addr); + +int spapr_populate_pci_devices(sPAPRPHBState *phb, + uint32_t xics_phandle, + void *fdt); + +#endif /* __HW_SPAPR_PCI_H__ */ From 7f7623662781fa152c5aa39fd63a2e8766516a2c Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Tue, 1 Nov 2011 20:59:32 +0000 Subject: [PATCH 25/25] Revert "PPC: Fail configure when libfdt is not available" This reverts commit f90a9d02401eeeec18a122b61ccccb91244f321c. Signed-off-by: Blue Swirl --- configure | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/configure b/configure index 28b76c07ab..850efc0f16 100755 --- a/configure +++ b/configure @@ -3454,16 +3454,7 @@ case "$target_arch2" in fi fi esac -if test "$fdt" != "yes" && test "$target_arch2" = "ppc" -o \ - "$target_arch2" = "ppc64" -o "$target_arch2" = "ppcemb"; then - echo - echo "Error: libfdt missing" - echo "The PowerPC target requires libfdt to work properly." - echo "Please make sure to have it and its development packages installed." - echo - exit 1 -fi -if test "$target_arch2" = "ppc64"; then +if test "$target_arch2" = "ppc64" -a "$fdt" = "yes"; then echo "CONFIG_PSERIES=y" >> $config_target_mak fi if test "$target_bigendian" = "yes" ; then