From 215e79c01c4e6f766eb9add56c56453e9ea1d948 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 24 Apr 2013 22:24:12 +0200 Subject: [PATCH 01/32] KVM: Don't assume that mpstate exists with in-kernel PIC always On PPC, we don't support MP state. So far it's not necessary and I'm not convinced yet that we really need to support it ever. However, the current idle logic in QEMU assumes that an in-kernel PIC also means we support MP state. This assumption is not true anymore. Let's split up the two cases into two different variables. That way PPC can expose an in-kernel PIC, while not implementing MP state. Signed-off-by: Alexander Graf CC: Jan Kiszka --- cpus.c | 2 +- include/sysemu/kvm.h | 10 ++++++++++ kvm-all.c | 2 ++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/cpus.c b/cpus.c index 86571f913c..20958e5a59 100644 --- a/cpus.c +++ b/cpus.c @@ -71,7 +71,7 @@ static bool cpu_thread_is_idle(CPUState *cpu) return true; } if (!cpu->halted || qemu_cpu_has_work(cpu) || - kvm_async_interrupts_enabled()) { + kvm_halt_in_kernel()) { return false; } return true; diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index fe8bc4077c..24c8e9569c 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -42,6 +42,7 @@ extern bool kvm_allowed; extern bool kvm_kernel_irqchip; extern bool kvm_async_interrupts_allowed; +extern bool kvm_halt_in_kernel_allowed; extern bool kvm_irqfds_allowed; extern bool kvm_msi_via_irqfd_allowed; extern bool kvm_gsi_routing_allowed; @@ -72,6 +73,14 @@ extern bool kvm_readonly_mem_allowed; */ #define kvm_async_interrupts_enabled() (kvm_async_interrupts_allowed) +/** + * kvm_halt_in_kernel + * + * Returns: true if halted cpus should still get a KVM_RUN ioctl to run + * inside of kernel space. This only works if MP state is implemented. + */ +#define kvm_halt_in_kernel() (kvm_halt_in_kernel_allowed) + /** * kvm_irqfds_enabled: * @@ -110,6 +119,7 @@ extern bool kvm_readonly_mem_allowed; #define kvm_enabled() (0) #define kvm_irqchip_in_kernel() (false) #define kvm_async_interrupts_enabled() (false) +#define kvm_halt_in_kernel() (false) #define kvm_irqfds_enabled() (false) #define kvm_msi_via_irqfd_enabled() (false) #define kvm_gsi_routing_allowed() (false) diff --git a/kvm-all.c b/kvm-all.c index 7a1684ed78..82ecebb784 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -107,6 +107,7 @@ struct KVMState KVMState *kvm_state; bool kvm_kernel_irqchip; bool kvm_async_interrupts_allowed; +bool kvm_halt_in_kernel_allowed; bool kvm_irqfds_allowed; bool kvm_msi_via_irqfd_allowed; bool kvm_gsi_routing_allowed; @@ -1303,6 +1304,7 @@ static int kvm_irqchip_create(KVMState *s) * interrupt delivery (though the reverse is not necessarily true) */ kvm_async_interrupts_allowed = true; + kvm_halt_in_kernel_allowed = true; kvm_init_irq_routing(s); From 7b7745930b1f14057b41a257524c559e62c5faa7 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 16 Apr 2013 15:58:13 +0200 Subject: [PATCH 02/32] KVM: Export kvm_init_irq_routing On PPC, we can have different types of interrupt controllers, so we really only know that we are going to use one when we created it. Export kvm_init_irq_routing() to common code, so that we don't have to call kvm_irqchip_create(). Signed-off-by: Alexander Graf --- include/sysemu/kvm.h | 1 + kvm-all.c | 4 ++-- kvm-stub.c | 4 ++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index 24c8e9569c..0a6e62a834 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -312,4 +312,5 @@ int kvm_irqchip_add_irqfd_notifier(KVMState *s, EventNotifier *n, int virq); int kvm_irqchip_remove_irqfd_notifier(KVMState *s, EventNotifier *n, int virq); void kvm_pc_gsi_handler(void *opaque, int n, int level); void kvm_pc_setup_irq_routing(bool pci_enabled); +void kvm_init_irq_routing(KVMState *s); #endif diff --git a/kvm-all.c b/kvm-all.c index 82ecebb784..a5ab2a3f8e 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -954,7 +954,7 @@ static void clear_gsi(KVMState *s, unsigned int gsi) s->used_gsi_bitmap[gsi / 32] &= ~(1U << (gsi % 32)); } -static void kvm_init_irq_routing(KVMState *s) +void kvm_init_irq_routing(KVMState *s) { int gsi_count, i; @@ -1242,7 +1242,7 @@ static int kvm_irqchip_assign_irqfd(KVMState *s, int fd, int virq, bool assign) #else /* !KVM_CAP_IRQ_ROUTING */ -static void kvm_init_irq_routing(KVMState *s) +void kvm_init_irq_routing(KVMState *s) { } diff --git a/kvm-stub.c b/kvm-stub.c index 5457fe8d9a..dec7a836df 100644 --- a/kvm-stub.c +++ b/kvm-stub.c @@ -122,6 +122,10 @@ int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg) return -ENOSYS; } +void kvm_init_irq_routing(KVMState *s) +{ +} + void kvm_irqchip_release_virq(KVMState *s, int virq) { } From d07cc1f12d8e15c167857852c39190d770763824 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 16 Apr 2013 15:05:22 +0200 Subject: [PATCH 03/32] KVM: MSI: Swap payload to native endianness The usual MSI injection mechanism writes msi.data into memory using an le32 wrapper. So on big endian guests, this swaps msg.data into the expected byte order. For irqfd however, we don't swap the payload right now, rendering in-kernel MPIC emulation broken on PowerPC. Swap msg.data to the correct endianness whenever we touch it. Signed-off-by: Alexander Graf --- kvm-all.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/kvm-all.c b/kvm-all.c index a5ab2a3f8e..76435f5759 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -1131,7 +1131,7 @@ static KVMMSIRoute *kvm_lookup_msi_route(KVMState *s, MSIMessage msg) QTAILQ_FOREACH(route, &s->msi_hashtab[hash], entry) { if (route->kroute.u.msi.address_lo == (uint32_t)msg.address && route->kroute.u.msi.address_hi == (msg.address >> 32) && - route->kroute.u.msi.data == msg.data) { + route->kroute.u.msi.data == le32_to_cpu(msg.data)) { return route; } } @@ -1146,7 +1146,7 @@ int kvm_irqchip_send_msi(KVMState *s, MSIMessage msg) if (s->direct_msi) { msi.address_lo = (uint32_t)msg.address; msi.address_hi = msg.address >> 32; - msi.data = msg.data; + msi.data = le32_to_cpu(msg.data); msi.flags = 0; memset(msi.pad, 0, sizeof(msi.pad)); @@ -1168,7 +1168,7 @@ int kvm_irqchip_send_msi(KVMState *s, MSIMessage msg) route->kroute.flags = 0; route->kroute.u.msi.address_lo = (uint32_t)msg.address; route->kroute.u.msi.address_hi = msg.address >> 32; - route->kroute.u.msi.data = msg.data; + route->kroute.u.msi.data = le32_to_cpu(msg.data); kvm_add_routing_entry(s, &route->kroute); @@ -1200,7 +1200,7 @@ int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg) kroute.flags = 0; kroute.u.msi.address_lo = (uint32_t)msg.address; kroute.u.msi.address_hi = msg.address >> 32; - kroute.u.msi.data = msg.data; + kroute.u.msi.data = le32_to_cpu(msg.data); kvm_add_routing_entry(s, &kroute); @@ -1220,7 +1220,7 @@ int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg) kroute.flags = 0; kroute.u.msi.address_lo = (uint32_t)msg.address; kroute.u.msi.address_hi = msg.address >> 32; - kroute.u.msi.data = msg.data; + kroute.u.msi.data = le32_to_cpu(msg.data); return kvm_update_routing_entry(s, &kroute); } From 8935a442cd3cf94f21fcc4386c1c07a7a5dd6887 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 15 Apr 2013 13:19:32 +0000 Subject: [PATCH 04/32] openpic: factor out some common defines into openpic.h ...for use by the KVM in-kernel irqchip stub. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/intc/openpic.c | 40 ++++++++++++++++++---------------------- include/hw/ppc/openpic.h | 11 +++++++++++ 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/hw/intc/openpic.c b/hw/intc/openpic.c index c78871445b..ae42149664 100644 --- a/hw/intc/openpic.c +++ b/hw/intc/openpic.c @@ -57,11 +57,7 @@ static const int debug_openpic = 0; } while (0) #define MAX_CPU 32 -#define MAX_SRC 256 -#define MAX_TMR 4 -#define MAX_IPI 4 #define MAX_MSI 8 -#define MAX_IRQ (MAX_SRC + MAX_IPI + MAX_TMR) #define VID 0x03 /* MPIC version ID */ /* OpenPIC capability flags */ @@ -78,7 +74,7 @@ static const int debug_openpic = 0; #define OPENPIC_SUMMARY_REG_START 0x3800 #define OPENPIC_SUMMARY_REG_SIZE 0x800 #define OPENPIC_SRC_REG_START 0x10000 -#define OPENPIC_SRC_REG_SIZE (MAX_SRC * 0x20) +#define OPENPIC_SRC_REG_SIZE (OPENPIC_MAX_SRC * 0x20) #define OPENPIC_CPU_REG_START 0x20000 #define OPENPIC_CPU_REG_SIZE 0x100 + ((MAX_CPU - 1) * 0x1000) @@ -86,8 +82,8 @@ static const int debug_openpic = 0; #define RAVEN_MAX_CPU 2 #define RAVEN_MAX_EXT 48 #define RAVEN_MAX_IRQ 64 -#define RAVEN_MAX_TMR MAX_TMR -#define RAVEN_MAX_IPI MAX_IPI +#define RAVEN_MAX_TMR OPENPIC_MAX_TMR +#define RAVEN_MAX_IPI OPENPIC_MAX_IPI /* Interrupt definitions */ #define RAVEN_FE_IRQ (RAVEN_MAX_EXT) /* Internal functional IRQ */ @@ -209,7 +205,7 @@ typedef struct IRQQueue { /* Round up to the nearest 64 IRQs so that the queue length * won't change when moving between 32 and 64 bit hosts. */ - unsigned long queue[BITS_TO_LONGS((MAX_IRQ + 63) & ~63)]; + unsigned long queue[BITS_TO_LONGS((OPENPIC_MAX_IRQ + 63) & ~63)]; int next; int priority; } IRQQueue; @@ -283,7 +279,7 @@ typedef struct OpenPICState { uint32_t spve; /* Spurious vector register */ uint32_t tfrr; /* Timer frequency reporting register */ /* Source registers */ - IRQSource src[MAX_IRQ]; + IRQSource src[OPENPIC_MAX_IRQ]; /* Local registers per output pin */ IRQDest dst[MAX_CPU]; uint32_t nb_cpus; @@ -291,7 +287,7 @@ typedef struct OpenPICState { struct { uint32_t tccr; /* Global timer current count register */ uint32_t tbcr; /* Global timer base count register */ - } timers[MAX_TMR]; + } timers[OPENPIC_MAX_TMR]; /* Shared MSI registers */ struct { uint32_t msir; /* Shared Message Signaled Interrupt Register */ @@ -503,7 +499,7 @@ static void openpic_set_irq(void *opaque, int n_IRQ, int level) OpenPICState *opp = opaque; IRQSource *src; - if (n_IRQ >= MAX_IRQ) { + if (n_IRQ >= OPENPIC_MAX_IRQ) { fprintf(stderr, "%s: IRQ %d out of range\n", __func__, n_IRQ); abort(); } @@ -576,7 +572,7 @@ static void openpic_reset(DeviceState *d) opp->dst[i].servicing.next = -1; } /* Initialise timers */ - for (i = 0; i < MAX_TMR; i++) { + for (i = 0; i < OPENPIC_MAX_TMR; i++) { opp->timers[i].tccr = 0; opp->timers[i].tbcr = TBCR_CI; } @@ -1182,7 +1178,7 @@ static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu) IRQ_resetbit(&dst->raised, irq); } - if ((irq >= opp->irq_ipi0) && (irq < (opp->irq_ipi0 + MAX_IPI))) { + if ((irq >= opp->irq_ipi0) && (irq < (opp->irq_ipi0 + OPENPIC_MAX_IPI))) { src->destmask &= ~(1 << cpu); if (src->destmask && !src->level) { /* trigger on CPUs that didn't know about it yet */ @@ -1381,7 +1377,7 @@ static void openpic_save(QEMUFile* f, void *opaque) sizeof(opp->dst[i].outputs_active)); } - for (i = 0; i < MAX_TMR; i++) { + for (i = 0; i < OPENPIC_MAX_TMR; i++) { qemu_put_be32s(f, &opp->timers[i].tccr); qemu_put_be32s(f, &opp->timers[i].tbcr); } @@ -1440,7 +1436,7 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id) sizeof(opp->dst[i].outputs_active)); } - for (i = 0; i < MAX_TMR; i++) { + for (i = 0; i < OPENPIC_MAX_TMR; i++) { qemu_get_be32s(f, &opp->timers[i].tccr); qemu_get_be32s(f, &opp->timers[i].tbcr); } @@ -1473,7 +1469,7 @@ typedef struct MemReg { static void fsl_common_init(OpenPICState *opp) { int i; - int virq = MAX_SRC; + int virq = OPENPIC_MAX_SRC; opp->vid = VID_REVISION_1_2; opp->vir = VIR_GENERIC; @@ -1481,14 +1477,14 @@ static void fsl_common_init(OpenPICState *opp) opp->tfrr_reset = 0; opp->ivpr_reset = IVPR_MASK_MASK; opp->idr_reset = 1 << 0; - opp->max_irq = MAX_IRQ; + opp->max_irq = OPENPIC_MAX_IRQ; opp->irq_ipi0 = virq; - virq += MAX_IPI; + virq += OPENPIC_MAX_IPI; opp->irq_tim0 = virq; - virq += MAX_TMR; + virq += OPENPIC_MAX_TMR; - assert(virq <= MAX_IRQ); + assert(virq <= OPENPIC_MAX_IRQ); opp->irq_msi = 224; @@ -1498,13 +1494,13 @@ static void fsl_common_init(OpenPICState *opp) } /* Internal interrupts, including message and MSI */ - for (i = 16; i < MAX_SRC; i++) { + for (i = 16; i < OPENPIC_MAX_SRC; i++) { opp->src[i].type = IRQ_TYPE_FSLINT; opp->src[i].level = true; } /* timers and IPIs */ - for (i = MAX_SRC; i < virq; i++) { + for (i = OPENPIC_MAX_SRC; i < virq; i++) { opp->src[i].type = IRQ_TYPE_FSLSPECIAL; opp->src[i].level = false; } diff --git a/include/hw/ppc/openpic.h b/include/hw/ppc/openpic.h index 9dcaf0e7cd..d873bb6419 100644 --- a/include/hw/ppc/openpic.h +++ b/include/hw/ppc/openpic.h @@ -1,6 +1,9 @@ #if !defined(__OPENPIC_H__) #define __OPENPIC_H__ +#include "qemu-common.h" +#include "hw/qdev.h" + /* OpenPIC have 5 outputs per CPU connected and one IRQ out single output */ enum { OPENPIC_OUTPUT_INT = 0, /* IRQ */ @@ -15,4 +18,12 @@ enum { #define OPENPIC_MODEL_FSL_MPIC_20 1 #define OPENPIC_MODEL_FSL_MPIC_42 2 +#define OPENPIC_MAX_SRC 256 +#define OPENPIC_MAX_TMR 4 +#define OPENPIC_MAX_IPI 4 +#define OPENPIC_MAX_IRQ (OPENPIC_MAX_SRC + OPENPIC_MAX_IPI + \ + OPENPIC_MAX_TMR) + +DeviceState *kvm_openpic_create(BusState *bus, int model); + #endif /* __OPENPIC_H__ */ From 82fc73b65c19fed0ee28aeb655d27de5ac9e78d5 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 15 Apr 2013 13:19:33 +0000 Subject: [PATCH 05/32] PPC: e500: factor out mpic init code KVM in-kernel MPIC support is going to expand this even more, so let's keep it contained. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/ppc/e500.c | 56 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index c9ae51211e..2d57b29286 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -472,6 +472,38 @@ static void ppce500_cpu_reset(void *opaque) mmubooke_create_initial_mapping(env); } +static qemu_irq *ppce500_init_mpic(PPCE500Params *params, MemoryRegion *ccsr, + qemu_irq **irqs) +{ + qemu_irq *mpic; + DeviceState *dev; + SysBusDevice *s; + int i, j, k; + + mpic = g_new(qemu_irq, 256); + dev = qdev_create(NULL, "openpic"); + qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus); + qdev_prop_set_uint32(dev, "model", params->mpic_version); + qdev_init_nofail(dev); + s = SYS_BUS_DEVICE(dev); + + k = 0; + for (i = 0; i < smp_cpus; i++) { + for (j = 0; j < OPENPIC_OUTPUT_NB; j++) { + sysbus_connect_irq(s, k++, irqs[i][j]); + } + } + + for (i = 0; i < 256; i++) { + mpic[i] = qdev_get_gpio_in(dev, i); + } + + memory_region_add_subregion(ccsr, MPC8544_MPIC_REGS_OFFSET, + s->mmio[0].memory); + + return mpic; +} + void ppce500_init(PPCE500Params *params) { MemoryRegion *address_space_mem = get_system_memory(); @@ -487,7 +519,7 @@ void ppce500_init(PPCE500Params *params) target_ulong initrd_base = 0; target_long initrd_size = 0; target_ulong cur_base = 0; - int i = 0, j, k; + int i; unsigned int pci_irq_nrs[4] = {1, 2, 3, 4}; qemu_irq **irqs, *mpic; DeviceState *dev; @@ -563,27 +595,7 @@ void ppce500_init(PPCE500Params *params) memory_region_add_subregion(address_space_mem, MPC8544_CCSRBAR_BASE, ccsr_addr_space); - /* MPIC */ - mpic = g_new(qemu_irq, 256); - dev = qdev_create(NULL, "openpic"); - qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus); - qdev_prop_set_uint32(dev, "model", params->mpic_version); - qdev_init_nofail(dev); - s = SYS_BUS_DEVICE(dev); - - k = 0; - for (i = 0; i < smp_cpus; i++) { - for (j = 0; j < OPENPIC_OUTPUT_NB; j++) { - sysbus_connect_irq(s, k++, irqs[i][j]); - } - } - - for (i = 0; i < 256; i++) { - mpic[i] = qdev_get_gpio_in(dev, i); - } - - memory_region_add_subregion(ccsr_addr_space, MPC8544_MPIC_REGS_OFFSET, - s->mmio[0].memory); + mpic = ppce500_init_mpic(params, ccsr_addr_space, irqs); /* Serial */ if (serial_hds[0]) { From cb925cf9230f77c096dae4b159a9449bc306256c Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 17 Apr 2013 01:11:55 +0200 Subject: [PATCH 06/32] KVM: PIC: Only commit irq routing when necessary The current logic updates KVM's view of our interrupt map every time we change it. While this is nice and bullet proof, it slows things down badly for me. QEMU spends about 3 seconds on every start telling KVM what news it has on its routing maps. Instead, let's just synchronize the whole irq routing map as a whole when we're done constructing it. For things that change during runtime, we can still update the routing table on demand. Signed-off-by: Alexander Graf --- hw/i386/kvm/ioapic.c | 1 + include/sysemu/kvm.h | 1 + kvm-all.c | 6 +++--- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/hw/i386/kvm/ioapic.c b/hw/i386/kvm/ioapic.c index a3bd519b4d..abfac3da7a 100644 --- a/hw/i386/kvm/ioapic.c +++ b/hw/i386/kvm/ioapic.c @@ -40,6 +40,7 @@ void kvm_pc_setup_irq_routing(bool pci_enabled) } } } + kvm_irqchip_commit_routes(s); } } diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index 0a6e62a834..a14cfe949e 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -230,6 +230,7 @@ int kvm_set_irq(KVMState *s, int irq, int level); int kvm_irqchip_send_msi(KVMState *s, MSIMessage msg); void kvm_irqchip_add_irq_route(KVMState *s, int gsi, int irqchip, int pin); +void kvm_irqchip_commit_routes(KVMState *s); void kvm_put_apic_state(DeviceState *d, struct kvm_lapic_state *kapic); void kvm_get_apic_state(DeviceState *d, struct kvm_lapic_state *kapic); diff --git a/kvm-all.c b/kvm-all.c index 76435f5759..c757dd262e 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -985,7 +985,7 @@ void kvm_init_irq_routing(KVMState *s) kvm_arch_init_irq_routing(s); } -static void kvm_irqchip_commit_routes(KVMState *s) +void kvm_irqchip_commit_routes(KVMState *s) { int ret; @@ -1019,8 +1019,6 @@ static void kvm_add_routing_entry(KVMState *s, new->u = entry->u; set_gsi(s, entry->gsi); - - kvm_irqchip_commit_routes(s); } static int kvm_update_routing_entry(KVMState *s, @@ -1171,6 +1169,7 @@ int kvm_irqchip_send_msi(KVMState *s, MSIMessage msg) route->kroute.u.msi.data = le32_to_cpu(msg.data); kvm_add_routing_entry(s, &route->kroute); + kvm_irqchip_commit_routes(s); QTAILQ_INSERT_TAIL(&s->msi_hashtab[kvm_hash_msi(msg.data)], route, entry); @@ -1203,6 +1202,7 @@ int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg) kroute.u.msi.data = le32_to_cpu(msg.data); kvm_add_routing_entry(s, &kroute); + kvm_irqchip_commit_routes(s); return virq; } From 4be1db86060d803f2335c08a483218eb6a8bd9eb Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 28 Jun 2013 13:47:15 +0200 Subject: [PATCH 07/32] PPC: Add non-kvm stub file There are cases where a kvm provided function is called from generic hw code that doesn't know whether kvm is available or not. Provide a stub file which can provide simple replacement functions for those cases. Signed-off-by: Alexander Graf Reviewed-by: Paolo Bonzini --- target-ppc/Makefile.objs | 1 + target-ppc/kvm-stub.c | 12 ++++++++++++ 2 files changed, 13 insertions(+) create mode 100644 target-ppc/kvm-stub.c diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs index 2c43c34a5c..6e78cb3624 100644 --- a/target-ppc/Makefile.objs +++ b/target-ppc/Makefile.objs @@ -5,6 +5,7 @@ obj-y += machine.o mmu_helper.o mmu-hash32.o obj-$(TARGET_PPC64) += mmu-hash64.o endif obj-$(CONFIG_KVM) += kvm.o kvm_ppc.o +obj-$(CONFIG_NO_KVM) += kvm-stub.o obj-y += excp_helper.o obj-y += fpu_helper.o obj-y += int_helper.o diff --git a/target-ppc/kvm-stub.c b/target-ppc/kvm-stub.c new file mode 100644 index 0000000000..0f5c27d154 --- /dev/null +++ b/target-ppc/kvm-stub.c @@ -0,0 +1,12 @@ +/* + * QEMU KVM PPC specific function stubs + * + * Copyright Freescale Inc. 2013 + * + * Author: Alexander Graf + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ +#include "qemu-common.h" From d85937e683f6ff4d68293cb24c780fb1f6820d2c Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Wed, 12 Jun 2013 15:32:51 -0500 Subject: [PATCH 08/32] kvm/openpic: in-kernel mpic support Enables support for the in-kernel MPIC that thas been merged into the KVM next branch. This includes irqfd/KVM_IRQ_LINE support from Alex Graf (along with some other improvements). Note from Alex regarding kvm_irqchip_create(): On x86, one would call kvm_irqchip_create() to initialize an in-kernel interrupt controller. That function then goes ahead and initializes global capability variables as well as the default irq routing table. On ppc, we can't call kvm_irqchip_create() because we can have different types of interrupt controllers. So we want to do all the things that function would do for us in the in-kernel device init handler. Signed-off-by: Scott Wood [agraf: squash in kvm_irqchip_commit_routes patch, fix non-kvm build, fix ppcemb] Signed-off-by: Alexander Graf --- default-configs/ppc-softmmu.mak | 1 + default-configs/ppc64-softmmu.mak | 1 + default-configs/ppcemb-softmmu.mak | 1 + hw/intc/Makefile.objs | 1 + hw/intc/openpic_kvm.c | 252 +++++++++++++++++++++++++++++ hw/ppc/e500.c | 79 ++++++++- include/hw/ppc/openpic.h | 2 +- target-ppc/kvm-stub.c | 6 + 8 files changed, 337 insertions(+), 6 deletions(-) create mode 100644 hw/intc/openpic_kvm.c diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak index bcaa52fb10..73e4cc5f63 100644 --- a/default-configs/ppc-softmmu.mak +++ b/default-configs/ppc-softmmu.mak @@ -43,5 +43,6 @@ CONFIG_XILINX=y CONFIG_XILINX_ETHLITE=y CONFIG_OPENPIC=y CONFIG_E500=y +CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM)) # For PReP CONFIG_MC146818RTC=y diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak index 8b7874ea6a..cb279cbcb6 100644 --- a/default-configs/ppc64-softmmu.mak +++ b/default-configs/ppc64-softmmu.mak @@ -44,6 +44,7 @@ CONFIG_XILINX_ETHLITE=y CONFIG_OPENPIC=y CONFIG_PSERIES=y CONFIG_E500=y +CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM)) # For pSeries CONFIG_PCI_HOTPLUG=y # For PReP diff --git a/default-configs/ppcemb-softmmu.mak b/default-configs/ppcemb-softmmu.mak index 61920ffe63..e3b5e50360 100644 --- a/default-configs/ppcemb-softmmu.mak +++ b/default-configs/ppcemb-softmmu.mak @@ -38,5 +38,6 @@ CONFIG_XILINX=y CONFIG_XILINX_ETHLITE=y CONFIG_OPENPIC=y CONFIG_E500=y +CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM)) # For PReP CONFIG_MC146818RTC=y diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs index 3e68d2eba8..2ba49d0e41 100644 --- a/hw/intc/Makefile.objs +++ b/hw/intc/Makefile.objs @@ -20,4 +20,5 @@ obj-$(CONFIG_GRLIB) += grlib_irqmp.o obj-$(CONFIG_IOAPIC) += ioapic.o obj-$(CONFIG_OMAP) += omap_intc.o obj-$(CONFIG_OPENPIC) += openpic.o +obj-$(CONFIG_OPENPIC_KVM) += openpic_kvm.o obj-$(CONFIG_SH4) += sh_intc.o diff --git a/hw/intc/openpic_kvm.c b/hw/intc/openpic_kvm.c new file mode 100644 index 0000000000..17d0a356de --- /dev/null +++ b/hw/intc/openpic_kvm.c @@ -0,0 +1,252 @@ +/* + * KVM in-kernel OpenPIC + * + * Copyright 2013 Freescale Semiconductor, Inc. + * + * 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 +#include "exec/address-spaces.h" +#include "hw/hw.h" +#include "hw/ppc/openpic.h" +#include "hw/pci/msi.h" +#include "hw/sysbus.h" +#include "sysemu/kvm.h" +#include "qemu/log.h" + +typedef struct KVMOpenPICState { + SysBusDevice busdev; + MemoryRegion mem; + MemoryListener mem_listener; + uint32_t fd; + uint32_t model; +} KVMOpenPICState; + +static void kvm_openpic_set_irq(void *opaque, int n_IRQ, int level) +{ + kvm_set_irq(kvm_state, n_IRQ, level); +} + +static void kvm_openpic_reset(DeviceState *d) +{ + qemu_log_mask(LOG_UNIMP, "%s: unimplemented\n", __func__); +} + +static void kvm_openpic_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + KVMOpenPICState *opp = opaque; + struct kvm_device_attr attr; + uint32_t val32 = val; + int ret; + + attr.group = KVM_DEV_MPIC_GRP_REGISTER; + attr.attr = addr; + attr.addr = (uint64_t)(unsigned long)&val32; + + ret = ioctl(opp->fd, KVM_SET_DEVICE_ATTR, &attr); + if (ret < 0) { + qemu_log_mask(LOG_UNIMP, "%s: %s %" PRIx64 "\n", __func__, + strerror(errno), attr.attr); + } +} + +static uint64_t kvm_openpic_read(void *opaque, hwaddr addr, unsigned size) +{ + KVMOpenPICState *opp = opaque; + struct kvm_device_attr attr; + uint32_t val = 0xdeadbeef; + int ret; + + attr.group = KVM_DEV_MPIC_GRP_REGISTER; + attr.attr = addr; + attr.addr = (uint64_t)(unsigned long)&val; + + ret = ioctl(opp->fd, KVM_GET_DEVICE_ATTR, &attr); + if (ret < 0) { + qemu_log_mask(LOG_UNIMP, "%s: %s %" PRIx64 "\n", __func__, + strerror(errno), attr.attr); + return 0; + } + + return val; +} + +static const MemoryRegionOps kvm_openpic_mem_ops = { + .write = kvm_openpic_write, + .read = kvm_openpic_read, + .endianness = DEVICE_BIG_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static void kvm_openpic_region_add(MemoryListener *listener, + MemoryRegionSection *section) +{ + KVMOpenPICState *opp = container_of(listener, KVMOpenPICState, + mem_listener); + struct kvm_device_attr attr; + uint64_t reg_base; + int ret; + + if (section->address_space != &address_space_memory) { + abort(); + } + + reg_base = section->offset_within_address_space; + + attr.group = KVM_DEV_MPIC_GRP_MISC; + attr.attr = KVM_DEV_MPIC_BASE_ADDR; + attr.addr = (uint64_t)(unsigned long)®_base; + + ret = ioctl(opp->fd, KVM_SET_DEVICE_ATTR, &attr); + if (ret < 0) { + fprintf(stderr, "%s: %s %" PRIx64 "\n", __func__, + strerror(errno), reg_base); + } +} + +static void kvm_openpic_region_del(MemoryListener *listener, + MemoryRegionSection *section) +{ + KVMOpenPICState *opp = container_of(listener, KVMOpenPICState, + mem_listener); + struct kvm_device_attr attr; + uint64_t reg_base = 0; + int ret; + + attr.group = KVM_DEV_MPIC_GRP_MISC; + attr.attr = KVM_DEV_MPIC_BASE_ADDR; + attr.addr = (uint64_t)(unsigned long)®_base; + + ret = ioctl(opp->fd, KVM_SET_DEVICE_ATTR, &attr); + if (ret < 0) { + fprintf(stderr, "%s: %s %" PRIx64 "\n", __func__, + strerror(errno), reg_base); + } +} + +static int kvm_openpic_init(SysBusDevice *dev) +{ + KVMState *s = kvm_state; + KVMOpenPICState *opp = FROM_SYSBUS(typeof(*opp), dev); + int kvm_openpic_model; + struct kvm_create_device cd = {0}; + int ret, i; + + if (!kvm_check_extension(s, KVM_CAP_DEVICE_CTRL)) { + return -EINVAL; + } + + switch (opp->model) { + case OPENPIC_MODEL_FSL_MPIC_20: + kvm_openpic_model = KVM_DEV_TYPE_FSL_MPIC_20; + break; + + case OPENPIC_MODEL_FSL_MPIC_42: + kvm_openpic_model = KVM_DEV_TYPE_FSL_MPIC_42; + break; + + default: + return -EINVAL; + } + + cd.type = kvm_openpic_model; + ret = kvm_vm_ioctl(s, KVM_CREATE_DEVICE, &cd); + if (ret < 0) { + qemu_log_mask(LOG_UNIMP, "%s: can't create device %d: %s\n", + __func__, cd.type, strerror(errno)); + return -EINVAL; + } + opp->fd = cd.fd; + + memory_region_init_io(&opp->mem, &kvm_openpic_mem_ops, opp, + "kvm-openpic", 0x40000); + + sysbus_init_mmio(dev, &opp->mem); + qdev_init_gpio_in(&dev->qdev, kvm_openpic_set_irq, OPENPIC_MAX_IRQ); + + opp->mem_listener.region_add = kvm_openpic_region_add; + opp->mem_listener.region_add = kvm_openpic_region_del; + memory_listener_register(&opp->mem_listener, &address_space_memory); + + /* indicate pic capabilities */ + msi_supported = true; + kvm_kernel_irqchip = true; + kvm_async_interrupts_allowed = true; + + /* set up irq routing */ + kvm_init_irq_routing(kvm_state); + for (i = 0; i < 256; ++i) { + kvm_irqchip_add_irq_route(kvm_state, i, 0, i); + } + + kvm_irqfds_allowed = true; + kvm_msi_via_irqfd_allowed = true; + kvm_gsi_routing_allowed = true; + + kvm_irqchip_commit_routes(s); + + return 0; +} + +int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs) +{ + KVMOpenPICState *opp = FROM_SYSBUS(typeof(*opp), SYS_BUS_DEVICE(d)); + struct kvm_enable_cap encap = {}; + + encap.cap = KVM_CAP_IRQ_MPIC; + encap.args[0] = opp->fd; + encap.args[1] = cs->cpu_index; + + return kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &encap); +} + +static Property kvm_openpic_properties[] = { + DEFINE_PROP_UINT32("model", KVMOpenPICState, model, + OPENPIC_MODEL_FSL_MPIC_20), + DEFINE_PROP_END_OF_LIST(), +}; + +static void kvm_openpic_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = kvm_openpic_init; + dc->props = kvm_openpic_properties; + dc->reset = kvm_openpic_reset; +} + +static const TypeInfo kvm_openpic_info = { + .name = "kvm-openpic", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(KVMOpenPICState), + .class_init = kvm_openpic_class_init, +}; + +static void kvm_openpic_register_types(void) +{ + type_register_static(&kvm_openpic_info); +} + +type_init(kvm_openpic_register_types) diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 2d57b29286..d38a688fa1 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -472,18 +472,17 @@ static void ppce500_cpu_reset(void *opaque) mmubooke_create_initial_mapping(env); } -static qemu_irq *ppce500_init_mpic(PPCE500Params *params, MemoryRegion *ccsr, - qemu_irq **irqs) +static DeviceState *ppce500_init_mpic_qemu(PPCE500Params *params, + qemu_irq **irqs) { - qemu_irq *mpic; DeviceState *dev; SysBusDevice *s; int i, j, k; - mpic = g_new(qemu_irq, 256); dev = qdev_create(NULL, "openpic"); - qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus); qdev_prop_set_uint32(dev, "model", params->mpic_version); + qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus); + qdev_init_nofail(dev); s = SYS_BUS_DEVICE(dev); @@ -494,10 +493,80 @@ static qemu_irq *ppce500_init_mpic(PPCE500Params *params, MemoryRegion *ccsr, } } + return dev; +} + +static DeviceState *ppce500_init_mpic_kvm(PPCE500Params *params, + qemu_irq **irqs) +{ + DeviceState *dev; + CPUPPCState *env; + CPUState *cs; + int r; + + dev = qdev_create(NULL, "kvm-openpic"); + qdev_prop_set_uint32(dev, "model", params->mpic_version); + + r = qdev_init(dev); + if (r) { + return NULL; + } + + for (env = first_cpu; env != NULL; env = env->next_cpu) { + cs = ENV_GET_CPU(env); + + if (kvm_openpic_connect_vcpu(dev, cs)) { + fprintf(stderr, "%s: failed to connect vcpu to irqchip\n", + __func__); + abort(); + } + } + + return dev; +} + +static qemu_irq *ppce500_init_mpic(PPCE500Params *params, MemoryRegion *ccsr, + qemu_irq **irqs) +{ + QemuOptsList *list; + qemu_irq *mpic; + DeviceState *dev = NULL; + SysBusDevice *s; + int i; + + mpic = g_new(qemu_irq, 256); + + if (kvm_enabled()) { + bool irqchip_allowed = true, irqchip_required = false; + + list = qemu_find_opts("machine"); + if (!QTAILQ_EMPTY(&list->head)) { + irqchip_allowed = qemu_opt_get_bool(QTAILQ_FIRST(&list->head), + "kernel_irqchip", true); + irqchip_required = qemu_opt_get_bool(QTAILQ_FIRST(&list->head), + "kernel_irqchip", false); + } + + if (irqchip_allowed) { + dev = ppce500_init_mpic_kvm(params, irqs); + } + + if (irqchip_required && !dev) { + fprintf(stderr, "%s: irqchip requested but unavailable\n", + __func__); + abort(); + } + } + + if (!dev) { + dev = ppce500_init_mpic_qemu(params, irqs); + } + for (i = 0; i < 256; i++) { mpic[i] = qdev_get_gpio_in(dev, i); } + s = SYS_BUS_DEVICE(dev); memory_region_add_subregion(ccsr, MPC8544_MPIC_REGS_OFFSET, s->mmio[0].memory); diff --git a/include/hw/ppc/openpic.h b/include/hw/ppc/openpic.h index d873bb6419..1fe4865e1d 100644 --- a/include/hw/ppc/openpic.h +++ b/include/hw/ppc/openpic.h @@ -24,6 +24,6 @@ enum { #define OPENPIC_MAX_IRQ (OPENPIC_MAX_SRC + OPENPIC_MAX_IPI + \ OPENPIC_MAX_TMR) -DeviceState *kvm_openpic_create(BusState *bus, int model); +int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs); #endif /* __OPENPIC_H__ */ diff --git a/target-ppc/kvm-stub.c b/target-ppc/kvm-stub.c index 0f5c27d154..ee3f5d2f72 100644 --- a/target-ppc/kvm-stub.c +++ b/target-ppc/kvm-stub.c @@ -10,3 +10,9 @@ * */ #include "qemu-common.h" +#include "hw/ppc/openpic.h" + +int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs) +{ + return -EINVAL; +} From e1766344fd1d3cb7421f734f89a9356fdec98398 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Tue, 18 Jun 2013 03:58:07 +0200 Subject: [PATCH 09/32] intc/openpic: QOM'ify MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce type constant and cast macro. Signed-off-by: Andreas Färber Reviewed-by: Peter Crosthwaite Signed-off-by: Alexander Graf --- hw/intc/openpic.c | 17 +++++++++++------ hw/ppc/e500.c | 2 +- hw/ppc/mac_newworld.c | 2 +- include/hw/ppc/openpic.h | 2 ++ 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/hw/intc/openpic.c b/hw/intc/openpic.c index ae42149664..fc2d104006 100644 --- a/hw/intc/openpic.c +++ b/hw/intc/openpic.c @@ -251,8 +251,13 @@ typedef struct IRQDest { uint32_t outputs_active[OPENPIC_OUTPUT_NB]; } IRQDest; +#define OPENPIC(obj) OBJECT_CHECK(OpenPICState, (obj), TYPE_OPENPIC) + typedef struct OpenPICState { - SysBusDevice busdev; + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + MemoryRegion mem; /* Behavior control */ @@ -533,7 +538,7 @@ static void openpic_set_irq(void *opaque, int n_IRQ, int level) static void openpic_reset(DeviceState *d) { - OpenPICState *opp = FROM_SYSBUS(typeof(*opp), SYS_BUS_DEVICE(d)); + OpenPICState *opp = OPENPIC(d); int i; opp->gcr = GCR_RESET; @@ -699,7 +704,7 @@ static void openpic_gcr_write(OpenPICState *opp, uint64_t val) bool mpic_proxy = false; if (val & GCR_RESET) { - openpic_reset(&opp->busdev.qdev); + openpic_reset(DEVICE(opp)); return; } @@ -1524,7 +1529,7 @@ static void map_list(OpenPICState *opp, const MemReg *list, int *count) static int openpic_init(SysBusDevice *dev) { - OpenPICState *opp = FROM_SYSBUS(typeof (*opp), dev); + OpenPICState *opp = OPENPIC(dev); int i, j; int list_count = 0; static const MemReg list_le[] = { @@ -1617,7 +1622,7 @@ static int openpic_init(SysBusDevice *dev) } } - register_savevm(&opp->busdev.qdev, "openpic", 0, 2, + register_savevm(DEVICE(opp), "openpic", 0, 2, openpic_save, openpic_load, opp); sysbus_init_mmio(dev, &opp->mem); @@ -1643,7 +1648,7 @@ static void openpic_class_init(ObjectClass *klass, void *data) } static const TypeInfo openpic_info = { - .name = "openpic", + .name = TYPE_OPENPIC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(OpenPICState), .class_init = openpic_class_init, diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index d38a688fa1..3797fbca8f 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -479,7 +479,7 @@ static DeviceState *ppce500_init_mpic_qemu(PPCE500Params *params, SysBusDevice *s; int i, j, k; - dev = qdev_create(NULL, "openpic"); + dev = qdev_create(NULL, TYPE_OPENPIC); qdev_prop_set_uint32(dev, "model", params->mpic_version); qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus); diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index ce44e95d53..61c25a4357 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -329,7 +329,7 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) pic = g_new(qemu_irq, 64); - dev = qdev_create(NULL, "openpic"); + dev = qdev_create(NULL, TYPE_OPENPIC); qdev_prop_set_uint32(dev, "model", OPENPIC_MODEL_RAVEN); qdev_init_nofail(dev); s = SYS_BUS_DEVICE(dev); diff --git a/include/hw/ppc/openpic.h b/include/hw/ppc/openpic.h index 1fe4865e1d..ef3f5c3e97 100644 --- a/include/hw/ppc/openpic.h +++ b/include/hw/ppc/openpic.h @@ -4,6 +4,8 @@ #include "qemu-common.h" #include "hw/qdev.h" +#define TYPE_OPENPIC "openpic" + /* OpenPIC have 5 outputs per CPU connected and one IRQ out single output */ enum { OPENPIC_OUTPUT_INT = 0, /* IRQ */ From cbe72019b1432b368dde7c6cd3e270fc221de085 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Tue, 18 Jun 2013 03:58:08 +0200 Subject: [PATCH 10/32] intc/openpic: Convert to QOM realize MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split qdev initfn into instance_init and realize functions. Change one occurrence of "klass" while at it. Signed-off-by: Andreas Färber Reviewed-by: Peter Crosthwaite Signed-off-by: Alexander Graf --- hw/intc/openpic.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/hw/intc/openpic.c b/hw/intc/openpic.c index fc2d104006..a26c641699 100644 --- a/hw/intc/openpic.c +++ b/hw/intc/openpic.c @@ -1527,8 +1527,16 @@ static void map_list(OpenPICState *opp, const MemReg *list, int *count) } } -static int openpic_init(SysBusDevice *dev) +static void openpic_init(Object *obj) { + OpenPICState *opp = OPENPIC(obj); + + memory_region_init(&opp->mem, "openpic", 0x40000); +} + +static void openpic_realize(DeviceState *dev, Error **errp) +{ + SysBusDevice *d = SYS_BUS_DEVICE(dev); OpenPICState *opp = OPENPIC(dev); int i, j; int list_count = 0; @@ -1562,8 +1570,6 @@ static int openpic_init(SysBusDevice *dev) {NULL} }; - memory_region_init(&opp->mem, "openpic", 0x40000); - switch (opp->model) { case OPENPIC_MODEL_FSL_MPIC_20: default: @@ -1606,9 +1612,9 @@ static int openpic_init(SysBusDevice *dev) opp->brr1 = -1; opp->mpic_mode_mask = GCR_MODE_MIXED; - /* Only UP supported today */ if (opp->nb_cpus != 1) { - return -EINVAL; + error_setg(errp, "Only UP supported today"); + return; } map_list(opp, list_le, &list_count); @@ -1618,17 +1624,15 @@ static int openpic_init(SysBusDevice *dev) for (i = 0; i < opp->nb_cpus; i++) { opp->dst[i].irqs = g_new(qemu_irq, OPENPIC_OUTPUT_NB); for (j = 0; j < OPENPIC_OUTPUT_NB; j++) { - sysbus_init_irq(dev, &opp->dst[i].irqs[j]); + sysbus_init_irq(d, &opp->dst[i].irqs[j]); } } - register_savevm(DEVICE(opp), "openpic", 0, 2, + register_savevm(dev, "openpic", 0, 2, openpic_save, openpic_load, opp); - sysbus_init_mmio(dev, &opp->mem); - qdev_init_gpio_in(&dev->qdev, openpic_set_irq, opp->max_irq); - - return 0; + sysbus_init_mmio(d, &opp->mem); + qdev_init_gpio_in(dev, openpic_set_irq, opp->max_irq); } static Property openpic_properties[] = { @@ -1637,12 +1641,11 @@ static Property openpic_properties[] = { DEFINE_PROP_END_OF_LIST(), }; -static void openpic_class_init(ObjectClass *klass, void *data) +static void openpic_class_init(ObjectClass *oc, void *data) { - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(oc); - k->init = openpic_init; + dc->realize = openpic_realize; dc->props = openpic_properties; dc->reset = openpic_reset; } @@ -1651,6 +1654,7 @@ static const TypeInfo openpic_info = { .name = TYPE_OPENPIC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(OpenPICState), + .instance_init = openpic_init, .class_init = openpic_class_init, }; From dd49c038c373329dc9e98e591677978ff2277d9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 16 Jun 2013 21:30:40 +0200 Subject: [PATCH 11/32] intc/openpic_kvm: Fix QOM and build issues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- hw/intc/openpic_kvm.c | 54 ++++++++++++++++++++++++---------------- hw/ppc/e500.c | 2 +- include/hw/ppc/openpic.h | 1 + 3 files changed, 35 insertions(+), 22 deletions(-) diff --git a/hw/intc/openpic_kvm.c b/hw/intc/openpic_kvm.c index 17d0a356de..6775879e0f 100644 --- a/hw/intc/openpic_kvm.c +++ b/hw/intc/openpic_kvm.c @@ -31,8 +31,14 @@ #include "sysemu/kvm.h" #include "qemu/log.h" +#define KVM_OPENPIC(obj) \ + OBJECT_CHECK(KVMOpenPICState, (obj), TYPE_KVM_OPENPIC) + typedef struct KVMOpenPICState { - SysBusDevice busdev; + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + MemoryRegion mem; MemoryListener mem_listener; uint32_t fd; @@ -145,16 +151,26 @@ static void kvm_openpic_region_del(MemoryListener *listener, } } -static int kvm_openpic_init(SysBusDevice *dev) +static void kvm_openpic_init(Object *obj) { + KVMOpenPICState *opp = KVM_OPENPIC(obj); + + memory_region_init_io(&opp->mem, &kvm_openpic_mem_ops, opp, + "kvm-openpic", 0x40000); +} + +static void kvm_openpic_realize(DeviceState *dev, Error **errp) +{ + SysBusDevice *d = SYS_BUS_DEVICE(dev); + KVMOpenPICState *opp = KVM_OPENPIC(dev); KVMState *s = kvm_state; - KVMOpenPICState *opp = FROM_SYSBUS(typeof(*opp), dev); int kvm_openpic_model; struct kvm_create_device cd = {0}; int ret, i; if (!kvm_check_extension(s, KVM_CAP_DEVICE_CTRL)) { - return -EINVAL; + error_setg(errp, "Kernel is lacking Device Control API"); + return; } switch (opp->model) { @@ -167,23 +183,21 @@ static int kvm_openpic_init(SysBusDevice *dev) break; default: - return -EINVAL; + error_setg(errp, "Unsupported OpenPIC model %" PRIu32, opp->model); + return; } cd.type = kvm_openpic_model; ret = kvm_vm_ioctl(s, KVM_CREATE_DEVICE, &cd); if (ret < 0) { - qemu_log_mask(LOG_UNIMP, "%s: can't create device %d: %s\n", - __func__, cd.type, strerror(errno)); - return -EINVAL; + error_setg(errp, "Can't create device %d: %s", + cd.type, strerror(errno)); + return; } opp->fd = cd.fd; - memory_region_init_io(&opp->mem, &kvm_openpic_mem_ops, opp, - "kvm-openpic", 0x40000); - - sysbus_init_mmio(dev, &opp->mem); - qdev_init_gpio_in(&dev->qdev, kvm_openpic_set_irq, OPENPIC_MAX_IRQ); + sysbus_init_mmio(d, &opp->mem); + qdev_init_gpio_in(dev, kvm_openpic_set_irq, OPENPIC_MAX_IRQ); opp->mem_listener.region_add = kvm_openpic_region_add; opp->mem_listener.region_add = kvm_openpic_region_del; @@ -205,13 +219,11 @@ static int kvm_openpic_init(SysBusDevice *dev) kvm_gsi_routing_allowed = true; kvm_irqchip_commit_routes(s); - - return 0; } int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs) { - KVMOpenPICState *opp = FROM_SYSBUS(typeof(*opp), SYS_BUS_DEVICE(d)); + KVMOpenPICState *opp = KVM_OPENPIC(d); struct kvm_enable_cap encap = {}; encap.cap = KVM_CAP_IRQ_MPIC; @@ -227,20 +239,20 @@ static Property kvm_openpic_properties[] = { DEFINE_PROP_END_OF_LIST(), }; -static void kvm_openpic_class_init(ObjectClass *klass, void *data) +static void kvm_openpic_class_init(ObjectClass *oc, void *data) { - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(oc); - k->init = kvm_openpic_init; + dc->realize = kvm_openpic_realize; dc->props = kvm_openpic_properties; dc->reset = kvm_openpic_reset; } static const TypeInfo kvm_openpic_info = { - .name = "kvm-openpic", + .name = TYPE_KVM_OPENPIC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(KVMOpenPICState), + .instance_init = kvm_openpic_init, .class_init = kvm_openpic_class_init, }; diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 3797fbca8f..38f799031a 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -504,7 +504,7 @@ static DeviceState *ppce500_init_mpic_kvm(PPCE500Params *params, CPUState *cs; int r; - dev = qdev_create(NULL, "kvm-openpic"); + dev = qdev_create(NULL, TYPE_KVM_OPENPIC); qdev_prop_set_uint32(dev, "model", params->mpic_version); r = qdev_init(dev); diff --git a/include/hw/ppc/openpic.h b/include/hw/ppc/openpic.h index ef3f5c3e97..ee67098cbc 100644 --- a/include/hw/ppc/openpic.h +++ b/include/hw/ppc/openpic.h @@ -26,6 +26,7 @@ enum { #define OPENPIC_MAX_IRQ (OPENPIC_MAX_SRC + OPENPIC_MAX_IPI + \ OPENPIC_MAX_TMR) +#define TYPE_KVM_OPENPIC "kvm-openpic" int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs); #endif /* __OPENPIC_H__ */ From 1f1a83f459dab7fbec9c5866a4d6a1ae16549edd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 9 Jun 2013 22:47:33 +0200 Subject: [PATCH 12/32] mpc8544_guts: Fix MemoryRegion name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 6544 -> 8544 Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- hw/ppc/mpc8544_guts.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ppc/mpc8544_guts.c b/hw/ppc/mpc8544_guts.c index 193beab2c2..98540a4514 100644 --- a/hw/ppc/mpc8544_guts.c +++ b/hw/ppc/mpc8544_guts.c @@ -115,7 +115,7 @@ static int mpc8544_guts_initfn(SysBusDevice *dev) s = FROM_SYSBUS(GutsState, SYS_BUS_DEVICE(dev)); memory_region_init_io(&s->iomem, &mpc8544_guts_ops, s, - "mpc6544.guts", MPC8544_GUTS_MMIO_SIZE); + "mpc8544.guts", MPC8544_GUTS_MMIO_SIZE); sysbus_init_mmio(dev, &s->iomem); return 0; From 43f691e9e248edca7b70680fd87b5be786cc4e01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 9 Jun 2013 22:47:34 +0200 Subject: [PATCH 13/32] mpc8544_guts: QOM'ify MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce type constant, cast macro and rename parent field. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- hw/ppc/mpc8544_guts.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/hw/ppc/mpc8544_guts.c b/hw/ppc/mpc8544_guts.c index 98540a4514..f623b040c9 100644 --- a/hw/ppc/mpc8544_guts.c +++ b/hw/ppc/mpc8544_guts.c @@ -51,8 +51,14 @@ #define MPC8544_GUTS_ADDR_SRDS2CR1 0xF10 #define MPC8544_GUTS_ADDR_SRDS2CR3 0xF18 +#define TYPE_MPC8544_GUTS "mpc8544-guts" +#define MPC8544_GUTS(obj) OBJECT_CHECK(GutsState, (obj), TYPE_MPC8544_GUTS) + struct GutsState { - SysBusDevice busdev; + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + MemoryRegion iomem; }; @@ -110,9 +116,7 @@ static const MemoryRegionOps mpc8544_guts_ops = { static int mpc8544_guts_initfn(SysBusDevice *dev) { - GutsState *s; - - s = FROM_SYSBUS(GutsState, SYS_BUS_DEVICE(dev)); + GutsState *s = MPC8544_GUTS(dev); memory_region_init_io(&s->iomem, &mpc8544_guts_ops, s, "mpc8544.guts", MPC8544_GUTS_MMIO_SIZE); @@ -129,7 +133,7 @@ static void mpc8544_guts_class_init(ObjectClass *klass, void *data) } static const TypeInfo mpc8544_guts_info = { - .name = "mpc8544-guts", + .name = TYPE_MPC8544_GUTS, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(GutsState), .class_init = mpc8544_guts_class_init, From 7587ea5bcbdeb08a204b4c1d5afe039d47d613fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 9 Jun 2013 22:47:35 +0200 Subject: [PATCH 14/32] mpc8544_guts: Turn qdev initfn into instance_init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SysBus can deal with NULL SysBusDeviceClass::init since 4ce5dae. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- hw/ppc/mpc8544_guts.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/hw/ppc/mpc8544_guts.c b/hw/ppc/mpc8544_guts.c index f623b040c9..d41f615522 100644 --- a/hw/ppc/mpc8544_guts.c +++ b/hw/ppc/mpc8544_guts.c @@ -114,29 +114,21 @@ static const MemoryRegionOps mpc8544_guts_ops = { }, }; -static int mpc8544_guts_initfn(SysBusDevice *dev) +static void mpc8544_guts_initfn(Object *obj) { - GutsState *s = MPC8544_GUTS(dev); + SysBusDevice *d = SYS_BUS_DEVICE(obj); + GutsState *s = MPC8544_GUTS(obj); memory_region_init_io(&s->iomem, &mpc8544_guts_ops, s, "mpc8544.guts", MPC8544_GUTS_MMIO_SIZE); - sysbus_init_mmio(dev, &s->iomem); - - return 0; -} - -static void mpc8544_guts_class_init(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = mpc8544_guts_initfn; + sysbus_init_mmio(d, &s->iomem); } static const TypeInfo mpc8544_guts_info = { .name = TYPE_MPC8544_GUTS, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(GutsState), - .class_init = mpc8544_guts_class_init, + .instance_init = mpc8544_guts_initfn, }; static void mpc8544_guts_register_types(void) From 1e3438df5a9e75355b36200f3bd8b94d1a32cc24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Fri, 22 Feb 2013 18:35:46 +0100 Subject: [PATCH 15/32] target-ppc: Drop redundant flags assignments from CPU families MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previous code has #define POWERPC_INSNS2_ PPC_NONE in some places for macrofied assignment to insns_flags2 field. PPC_NONE is defined as zero though and QOM classes are zero-initialized, so drop any pcc->insns_flags2 = PPC_NONE; assignments. PPC_NONE itself is still in use in translate.c. Suggested-by: Alexander Graf Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 45 ------------------------------------- 1 file changed, 45 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index fa5e09fb36..38116331c0 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -3147,7 +3147,6 @@ POWERPC_FAMILY(401)(ObjectClass *oc, void *data) PPC_CACHE_DCBZ | PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_4xx_COMMON | PPC_40x_EXCP; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x00000000000FD201ULL; pcc->mmu_model = POWERPC_MMU_REAL; pcc->excp_model = POWERPC_EXCP_40x; @@ -3195,7 +3194,6 @@ POWERPC_FAMILY(401x2)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | PPC_4xx_COMMON | PPC_40x_EXCP; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x00000000001FD231ULL; pcc->mmu_model = POWERPC_MMU_SOFT_4xx_Z; pcc->excp_model = POWERPC_EXCP_40x; @@ -3237,7 +3235,6 @@ POWERPC_FAMILY(401x3)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | PPC_4xx_COMMON | PPC_40x_EXCP; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x00000000001FD631ULL; pcc->mmu_model = POWERPC_MMU_SOFT_4xx_Z; pcc->excp_model = POWERPC_EXCP_40x; @@ -3285,7 +3282,6 @@ POWERPC_FAMILY(IOP480)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | PPC_4xx_COMMON | PPC_40x_EXCP; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x00000000001FD231ULL; pcc->mmu_model = POWERPC_MMU_SOFT_4xx_Z; pcc->excp_model = POWERPC_EXCP_40x; @@ -3325,7 +3321,6 @@ POWERPC_FAMILY(403)(ObjectClass *oc, void *data) PPC_CACHE_DCBZ | PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_4xx_COMMON | PPC_40x_EXCP; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000007D00DULL; pcc->mmu_model = POWERPC_MMU_REAL; pcc->excp_model = POWERPC_EXCP_40x; @@ -3385,7 +3380,6 @@ POWERPC_FAMILY(403GCX)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | PPC_4xx_COMMON | PPC_40x_EXCP; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000007D00DULL; pcc->mmu_model = POWERPC_MMU_SOFT_4xx_Z; pcc->excp_model = POWERPC_EXCP_40x; @@ -3444,7 +3438,6 @@ POWERPC_FAMILY(405)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | PPC_4xx_COMMON | PPC_405_MAC | PPC_40x_EXCP; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000006E630ULL; pcc->mmu_model = POWERPC_MMU_SOFT_4xx; pcc->excp_model = POWERPC_EXCP_40x; @@ -3538,7 +3531,6 @@ POWERPC_FAMILY(440EP)(ObjectClass *oc, void *data) PPC_MEM_TLBSYNC | PPC_MFTB | PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | PPC_440_SPEC; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000006FF30ULL; pcc->mmu_model = POWERPC_MMU_BOOKE; pcc->excp_model = POWERPC_EXCP_BOOKE; @@ -3611,7 +3603,6 @@ POWERPC_FAMILY(440GP)(ObjectClass *oc, void *data) PPC_MEM_TLBSYNC | PPC_TLBIVA | PPC_MFTB | PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | PPC_440_SPEC; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000006FF30ULL; pcc->mmu_model = POWERPC_MMU_BOOKE; pcc->excp_model = POWERPC_EXCP_BOOKE; @@ -3684,7 +3675,6 @@ POWERPC_FAMILY(440x4)(ObjectClass *oc, void *data) PPC_MEM_TLBSYNC | PPC_MFTB | PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | PPC_440_SPEC; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000006FF30ULL; pcc->mmu_model = POWERPC_MMU_BOOKE; pcc->excp_model = POWERPC_EXCP_BOOKE; @@ -3775,7 +3765,6 @@ POWERPC_FAMILY(440x5)(ObjectClass *oc, void *data) PPC_MEM_TLBSYNC | PPC_MFTB | PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | PPC_440_SPEC; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000006FF30ULL; pcc->mmu_model = POWERPC_MMU_BOOKE; pcc->excp_model = POWERPC_EXCP_BOOKE; @@ -3872,7 +3861,6 @@ POWERPC_FAMILY(460)(ObjectClass *oc, void *data) PPC_MEM_TLBSYNC | PPC_TLBIVA | PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | PPC_440_SPEC; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000006FF30ULL; pcc->mmu_model = POWERPC_MMU_BOOKE; pcc->excp_model = POWERPC_EXCP_BOOKE; @@ -3972,7 +3960,6 @@ POWERPC_FAMILY(460F)(ObjectClass *oc, void *data) PPC_MEM_TLBSYNC | PPC_TLBIVA | PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | PPC_440_SPEC; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000006FF30ULL; pcc->mmu_model = POWERPC_MMU_BOOKE; pcc->excp_model = POWERPC_EXCP_BOOKE; @@ -4006,7 +3993,6 @@ POWERPC_FAMILY(MPC5xx)(ObjectClass *oc, void *data) PPC_MEM_EIEIO | PPC_MEM_SYNC | PPC_CACHE_ICBI | PPC_FLOAT | PPC_FLOAT_STFIWX | PPC_MFTB; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000001FF43ULL; pcc->mmu_model = POWERPC_MMU_REAL; pcc->excp_model = POWERPC_EXCP_603; @@ -4039,7 +4025,6 @@ POWERPC_FAMILY(MPC8xx)(ObjectClass *oc, void *data) pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MEM_EIEIO | PPC_MEM_SYNC | PPC_CACHE_ICBI | PPC_MFTB; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000001F673ULL; pcc->mmu_model = POWERPC_MMU_MPC8xx; pcc->excp_model = POWERPC_EXCP_603; @@ -4106,7 +4091,6 @@ POWERPC_FAMILY(G2)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | PPC_SEGMENT | PPC_EXTERN; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000006FFF2ULL; pcc->mmu_model = POWERPC_MMU_SOFT_6xx; pcc->excp_model = POWERPC_EXCP_G2; @@ -4198,7 +4182,6 @@ POWERPC_FAMILY(G2LE)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | PPC_SEGMENT | PPC_EXTERN; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000007FFF3ULL; pcc->mmu_model = POWERPC_MMU_SOFT_6xx; pcc->excp_model = POWERPC_EXCP_G2; @@ -4339,7 +4322,6 @@ POWERPC_FAMILY(e200)(ObjectClass *oc, void *data) PPC_CACHE_DCBZ | PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_BOOKE; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000606FF30ULL; pcc->mmu_model = POWERPC_MMU_BOOKE206; pcc->excp_model = POWERPC_EXCP_BOOKE; @@ -4398,7 +4380,6 @@ POWERPC_FAMILY(e300)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | PPC_SEGMENT | PPC_EXTERN; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000007FFF3ULL; pcc->mmu_model = POWERPC_MMU_SOFT_6xx; pcc->excp_model = POWERPC_EXCP_603; @@ -4810,7 +4791,6 @@ POWERPC_FAMILY(601)(ObjectClass *oc, void *data) PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_SEGMENT | PPC_EXTERN; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000000FD70ULL; pcc->mmu_model = POWERPC_MMU_601; #if defined(CONFIG_SOFTMMU) @@ -4847,7 +4827,6 @@ POWERPC_FAMILY(601v)(ObjectClass *oc, void *data) PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_SEGMENT | PPC_EXTERN; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000000FD70ULL; pcc->mmu_model = POWERPC_MMU_601; #if defined(CONFIG_SOFTMMU) @@ -4900,7 +4879,6 @@ POWERPC_FAMILY(602)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_6xx_TLB | PPC_MEM_TLBSYNC | PPC_SEGMENT | PPC_602_SPEC; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x0000000000C7FF73ULL; /* XXX: 602 MMU is quite specific. Should add a special case */ pcc->mmu_model = POWERPC_MMU_SOFT_6xx; @@ -4953,7 +4931,6 @@ POWERPC_FAMILY(603)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | PPC_SEGMENT | PPC_EXTERN; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000007FF73ULL; pcc->mmu_model = POWERPC_MMU_SOFT_6xx; pcc->excp_model = POWERPC_EXCP_603; @@ -5010,7 +4987,6 @@ POWERPC_FAMILY(603E)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | PPC_SEGMENT | PPC_EXTERN; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000007FF73ULL; pcc->mmu_model = POWERPC_MMU_SOFT_6xx; pcc->excp_model = POWERPC_EXCP_603E; @@ -5056,7 +5032,6 @@ POWERPC_FAMILY(604)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_SEGMENT | PPC_EXTERN; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000005FF77ULL; pcc->mmu_model = POWERPC_MMU_32B; #if defined(CONFIG_SOFTMMU) @@ -5125,7 +5100,6 @@ POWERPC_FAMILY(604E)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_SEGMENT | PPC_EXTERN; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000005FF77ULL; pcc->mmu_model = POWERPC_MMU_32B; #if defined(CONFIG_SOFTMMU) @@ -5181,7 +5155,6 @@ POWERPC_FAMILY(740)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_SEGMENT | PPC_EXTERN; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000005FF77ULL; pcc->mmu_model = POWERPC_MMU_32B; #if defined(CONFIG_SOFTMMU) @@ -5245,7 +5218,6 @@ POWERPC_FAMILY(750)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_SEGMENT | PPC_EXTERN; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000005FF77ULL; pcc->mmu_model = POWERPC_MMU_32B; #if defined(CONFIG_SOFTMMU) @@ -5432,7 +5404,6 @@ POWERPC_FAMILY(750cl)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_SEGMENT | PPC_EXTERN; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000005FF77ULL; pcc->mmu_model = POWERPC_MMU_32B; #if defined(CONFIG_SOFTMMU) @@ -5500,7 +5471,6 @@ POWERPC_FAMILY(750cx)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_SEGMENT | PPC_EXTERN; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000005FF77ULL; pcc->mmu_model = POWERPC_MMU_32B; #if defined(CONFIG_SOFTMMU) @@ -5573,7 +5543,6 @@ POWERPC_FAMILY(750fx)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_SEGMENT | PPC_EXTERN; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000005FF77ULL; pcc->mmu_model = POWERPC_MMU_32B; #if defined(CONFIG_SOFTMMU) @@ -5646,7 +5615,6 @@ POWERPC_FAMILY(750gx)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_SEGMENT | PPC_EXTERN; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000005FF77ULL; pcc->mmu_model = POWERPC_MMU_32B; #if defined(CONFIG_SOFTMMU) @@ -5710,7 +5678,6 @@ POWERPC_FAMILY(745)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | PPC_SEGMENT | PPC_EXTERN; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000005FF77ULL; pcc->mmu_model = POWERPC_MMU_SOFT_6xx; pcc->excp_model = POWERPC_EXCP_7x5; @@ -5782,7 +5749,6 @@ POWERPC_FAMILY(755)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | PPC_SEGMENT | PPC_EXTERN; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000005FF77ULL; pcc->mmu_model = POWERPC_MMU_SOFT_6xx; pcc->excp_model = POWERPC_EXCP_7x5; @@ -5841,7 +5807,6 @@ POWERPC_FAMILY(7400)(ObjectClass *oc, void *data) PPC_MEM_TLBIA | PPC_SEGMENT | PPC_EXTERN | PPC_ALTIVEC; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000205FF77ULL; pcc->mmu_model = POWERPC_MMU_32B; #if defined(CONFIG_SOFTMMU) @@ -5910,7 +5875,6 @@ POWERPC_FAMILY(7410)(ObjectClass *oc, void *data) PPC_MEM_TLBIA | PPC_SEGMENT | PPC_EXTERN | PPC_ALTIVEC; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000205FF77ULL; pcc->mmu_model = POWERPC_MMU_32B; #if defined(CONFIG_SOFTMMU) @@ -6005,7 +5969,6 @@ POWERPC_FAMILY(7440)(ObjectClass *oc, void *data) PPC_MEM_TLBIA | PPC_74xx_TLB | PPC_SEGMENT | PPC_EXTERN | PPC_ALTIVEC; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000205FF77ULL; pcc->mmu_model = POWERPC_MMU_SOFT_74xx; pcc->excp_model = POWERPC_EXCP_74xx; @@ -6123,7 +6086,6 @@ POWERPC_FAMILY(7450)(ObjectClass *oc, void *data) PPC_MEM_TLBIA | PPC_74xx_TLB | PPC_SEGMENT | PPC_EXTERN | PPC_ALTIVEC; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000205FF77ULL; pcc->mmu_model = POWERPC_MMU_SOFT_74xx; pcc->excp_model = POWERPC_EXCP_74xx; @@ -6244,7 +6206,6 @@ POWERPC_FAMILY(7445)(ObjectClass *oc, void *data) PPC_MEM_TLBIA | PPC_74xx_TLB | PPC_SEGMENT | PPC_EXTERN | PPC_ALTIVEC; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000205FF77ULL; pcc->mmu_model = POWERPC_MMU_SOFT_74xx; pcc->excp_model = POWERPC_EXCP_74xx; @@ -6367,7 +6328,6 @@ POWERPC_FAMILY(7455)(ObjectClass *oc, void *data) PPC_MEM_TLBIA | PPC_74xx_TLB | PPC_SEGMENT | PPC_EXTERN | PPC_ALTIVEC; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000205FF77ULL; pcc->mmu_model = POWERPC_MMU_SOFT_74xx; pcc->excp_model = POWERPC_EXCP_74xx; @@ -6514,7 +6474,6 @@ POWERPC_FAMILY(7457)(ObjectClass *oc, void *data) PPC_MEM_TLBIA | PPC_74xx_TLB | PPC_SEGMENT | PPC_EXTERN | PPC_ALTIVEC; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000205FF77ULL; pcc->mmu_model = POWERPC_MMU_SOFT_74xx; pcc->excp_model = POWERPC_EXCP_74xx; @@ -6619,7 +6578,6 @@ POWERPC_FAMILY(970)(ObjectClass *oc, void *data) PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_64B | PPC_ALTIVEC | PPC_SEGMENT_64B | PPC_SLBI; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x900000000204FF36ULL; pcc->mmu_model = POWERPC_MMU_64B; #if defined(CONFIG_SOFTMMU) @@ -6732,7 +6690,6 @@ POWERPC_FAMILY(970FX)(ObjectClass *oc, void *data) PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_64B | PPC_ALTIVEC | PPC_SEGMENT_64B | PPC_SLBI; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x800000000204FF36ULL; pcc->mmu_model = POWERPC_MMU_64B; #if defined(CONFIG_SOFTMMU) @@ -6833,7 +6790,6 @@ POWERPC_FAMILY(970GX)(ObjectClass *oc, void *data) PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_64B | PPC_ALTIVEC | PPC_SEGMENT_64B | PPC_SLBI; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x800000000204FF36ULL; pcc->mmu_model = POWERPC_MMU_64B; #if defined(CONFIG_SOFTMMU) @@ -6934,7 +6890,6 @@ POWERPC_FAMILY(970MP)(ObjectClass *oc, void *data) PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_64B | PPC_ALTIVEC | PPC_SEGMENT_64B | PPC_SLBI; - pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x900000000204FF36ULL; pcc->mmu_model = POWERPC_MMU_64B; #if defined(CONFIG_SOFTMMU) From 9fea2ae25080ad790d7d904d01a1300a45a634eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= Date: Sat, 11 May 2013 21:03:50 +0200 Subject: [PATCH 16/32] ppc: do not register IABR SPR twice for 603e MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IABR SPR is already registered in gen_spr_603(), called from init_proc_603E(). Signed-off-by: Hervé Poussineau Reviewed-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 38116331c0..f365ad833c 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -4957,11 +4957,6 @@ static void init_proc_603E (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_IABR, "IABR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); /* Memory management */ gen_low_BATs(env); gen_6xx_7xx_soft_tlb(env, 64, 2); From 159f8286b760deace1008f5f68a46cadba337780 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Sat, 15 Jun 2013 11:51:50 +1000 Subject: [PATCH 17/32] target-ppc: Change default machine for 64-bit Currently, for qemu-system-ppc64, the default machine type is 'mac99'. The mac99 machine is not being actively maintained, and represents a bizarre hybrid of components that never actually existed as a real system. This patch changes the default machine to 'pseries', which is actively maintained and works well with most modern ppc64 Linux distributions as a guest. Signed-off-by: David Gibson [agraf: adjust commit message] Signed-off-by: Alexander Graf --- hw/ppc/mac_newworld.c | 3 --- hw/ppc/spapr.c | 1 + 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 61c25a4357..d8e4db3b6a 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -458,9 +458,6 @@ static QEMUMachine core99_machine = { .desc = "Mac99 based PowerMAC", .init = ppc_core99_init, .max_cpus = MAX_CPUS, -#ifdef TARGET_PPC64 - .is_default = 1, -#endif DEFAULT_MACHINE_OPTIONS, }; diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 218ea23da8..5363c3fe2c 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -971,6 +971,7 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) static QEMUMachine spapr_machine = { .name = "pseries", .desc = "pSeries Logical Partition (PAPR compliant)", + .is_default = 1, .init = ppc_spapr_init, .reset = ppc_spapr_reset, .block_default_type = IF_SCSI, From 210b580b106fa798149e28aa13c66b325a43204e Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Wed, 19 Jun 2013 15:40:30 -0500 Subject: [PATCH 18/32] spapr-rtas: add CPU argument to RTAS calls RTAS is a hypervisor provided binary blob that a guest loads and calls into to execute certain functions. It's similar to the vsyscall page in Linux or the short lived VMCI paravirt interface from VMware. The QEMU implementation of the RTAS blob is simply a passthrough that proxies all RTAS calls to the hypervisor via an hypercall. While we pass a CPU argument for hypercall handling in QEMU, we don't pass it for RTAS calls. Since some RTAs calls require making hypercalls (normally RTAS is implemented as guest code) we have nasty hacks to allow that. Add a CPU argument to RTAS call handling so we can more easily invoke hypercalls just as guest code would. Signed-off-by: Anthony Liguori Signed-off-by: Alexander Graf --- hw/nvram/spapr_nvram.c | 4 ++-- hw/ppc/spapr_events.c | 2 +- hw/ppc/spapr_hcall.c | 2 +- hw/ppc/spapr_pci.c | 13 +++++++------ hw/ppc/spapr_rtas.c | 21 +++++++++++---------- hw/ppc/spapr_vio.c | 6 ++++-- hw/ppc/xics.c | 12 ++++++++---- include/hw/ppc/spapr.h | 5 +++-- 8 files changed, 37 insertions(+), 28 deletions(-) diff --git a/hw/nvram/spapr_nvram.c b/hw/nvram/spapr_nvram.c index 1eb05c9075..eb4500e26f 100644 --- a/hw/nvram/spapr_nvram.c +++ b/hw/nvram/spapr_nvram.c @@ -44,7 +44,7 @@ typedef struct sPAPRNVRAM { #define DEFAULT_NVRAM_SIZE 65536 #define MAX_NVRAM_SIZE (UINT16_MAX * 16) -static void rtas_nvram_fetch(sPAPREnvironment *spapr, +static void rtas_nvram_fetch(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t token, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) @@ -91,7 +91,7 @@ static void rtas_nvram_fetch(sPAPREnvironment *spapr, rtas_st(rets, 1, (alen < 0) ? 0 : alen); } -static void rtas_nvram_store(sPAPREnvironment *spapr, +static void rtas_nvram_store(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t token, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c index c0d7e62f32..a69390e54e 100644 --- a/hw/ppc/spapr_events.c +++ b/hw/ppc/spapr_events.c @@ -277,7 +277,7 @@ static void spapr_powerdown_req(Notifier *n, void *opaque) qemu_irq_pulse(xics_get_qirq(spapr->icp, spapr->epow_irq)); } -static void check_exception(sPAPREnvironment *spapr, +static void check_exception(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t token, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 8f0b7e8076..e6f321d538 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -525,7 +525,7 @@ static target_ulong h_rtas(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t nargs = ldl_be_phys(rtas_r3 + 4); uint32_t nret = ldl_be_phys(rtas_r3 + 8); - return spapr_rtas_call(spapr, token, nargs, rtas_r3 + 12, + return spapr_rtas_call(cpu, spapr, token, nargs, rtas_r3 + 12, nret, rtas_r3 + 12 + 4*nargs); } diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 04e836257c..c8c12c8241 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -119,7 +119,7 @@ static void finish_read_pci_config(sPAPREnvironment *spapr, uint64_t buid, rtas_st(rets, 1, val); } -static void rtas_ibm_read_pci_config(sPAPREnvironment *spapr, +static void rtas_ibm_read_pci_config(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t token, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) @@ -139,7 +139,7 @@ static void rtas_ibm_read_pci_config(sPAPREnvironment *spapr, finish_read_pci_config(spapr, buid, addr, size, rets); } -static void rtas_read_pci_config(sPAPREnvironment *spapr, +static void rtas_read_pci_config(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t token, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) @@ -185,7 +185,7 @@ static void finish_write_pci_config(sPAPREnvironment *spapr, uint64_t buid, rtas_st(rets, 0, 0); } -static void rtas_ibm_write_pci_config(sPAPREnvironment *spapr, +static void rtas_ibm_write_pci_config(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t token, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) @@ -206,7 +206,7 @@ static void rtas_ibm_write_pci_config(sPAPREnvironment *spapr, finish_write_pci_config(spapr, buid, addr, size, val, rets); } -static void rtas_write_pci_config(sPAPREnvironment *spapr, +static void rtas_write_pci_config(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t token, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) @@ -277,7 +277,7 @@ static void spapr_msi_setmsg(PCIDevice *pdev, hwaddr addr, } } -static void rtas_ibm_change_msi(sPAPREnvironment *spapr, +static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t token, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) @@ -374,7 +374,8 @@ static void rtas_ibm_change_msi(sPAPREnvironment *spapr, trace_spapr_pci_rtas_ibm_change_msi(func, req_num); } -static void rtas_ibm_query_interrupt_source_number(sPAPREnvironment *spapr, +static void rtas_ibm_query_interrupt_source_number(PowerPCCPU *cpu, + sPAPREnvironment *spapr, uint32_t token, uint32_t nargs, target_ulong args, diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index 42ed7dc093..394ce05ba2 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -38,7 +38,7 @@ #define TOKEN_BASE 0x2000 #define TOKEN_MAX 0x100 -static void rtas_display_character(sPAPREnvironment *spapr, +static void rtas_display_character(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t token, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) @@ -54,7 +54,7 @@ static void rtas_display_character(sPAPREnvironment *spapr, } } -static void rtas_get_time_of_day(sPAPREnvironment *spapr, +static void rtas_get_time_of_day(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t token, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) @@ -78,7 +78,7 @@ static void rtas_get_time_of_day(sPAPREnvironment *spapr, rtas_st(rets, 7, 0); /* we don't do nanoseconds */ } -static void rtas_set_time_of_day(sPAPREnvironment *spapr, +static void rtas_set_time_of_day(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t token, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) @@ -99,7 +99,7 @@ static void rtas_set_time_of_day(sPAPREnvironment *spapr, rtas_st(rets, 0, 0); /* Success */ } -static void rtas_power_off(sPAPREnvironment *spapr, +static void rtas_power_off(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t token, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) { @@ -111,7 +111,7 @@ static void rtas_power_off(sPAPREnvironment *spapr, rtas_st(rets, 0, 0); } -static void rtas_system_reboot(sPAPREnvironment *spapr, +static void rtas_system_reboot(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t token, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) @@ -124,7 +124,8 @@ static void rtas_system_reboot(sPAPREnvironment *spapr, rtas_st(rets, 0, 0); } -static void rtas_query_cpu_stopped_state(sPAPREnvironment *spapr, +static void rtas_query_cpu_stopped_state(PowerPCCPU *cpu_, + sPAPREnvironment *spapr, uint32_t token, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) @@ -154,7 +155,7 @@ static void rtas_query_cpu_stopped_state(sPAPREnvironment *spapr, rtas_st(rets, 0, -3); } -static void rtas_start_cpu(sPAPREnvironment *spapr, +static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPREnvironment *spapr, uint32_t token, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) @@ -208,7 +209,7 @@ static struct rtas_call { struct rtas_call *rtas_next = rtas_table; -target_ulong spapr_rtas_call(sPAPREnvironment *spapr, +target_ulong spapr_rtas_call(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t token, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) { @@ -217,7 +218,7 @@ target_ulong spapr_rtas_call(sPAPREnvironment *spapr, struct rtas_call *call = rtas_table + (token - TOKEN_BASE); if (call->fn) { - call->fn(spapr, token, nargs, args, nret, rets); + call->fn(cpu, spapr, token, nargs, args, nret, rets); return H_SUCCESS; } } @@ -227,7 +228,7 @@ target_ulong spapr_rtas_call(sPAPREnvironment *spapr, * machines) without looking it up in the device tree. This * special case makes this work */ if (token == 0xa) { - rtas_display_character(spapr, 0xa, nargs, args, nret, rets); + rtas_display_character(cpu, spapr, 0xa, nargs, args, nret, rets); return H_SUCCESS; } diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c index 3c5a655ad7..9c18741cea 100644 --- a/hw/ppc/spapr_vio.c +++ b/hw/ppc/spapr_vio.c @@ -321,7 +321,8 @@ static void spapr_vio_quiesce_one(VIOsPAPRDevice *dev) free_crq(dev); } -static void rtas_set_tce_bypass(sPAPREnvironment *spapr, uint32_t token, +static void rtas_set_tce_bypass(PowerPCCPU *cpu, sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) { @@ -351,7 +352,8 @@ static void rtas_set_tce_bypass(sPAPREnvironment *spapr, uint32_t token, rtas_st(rets, 0, 0); } -static void rtas_quiesce(sPAPREnvironment *spapr, uint32_t token, +static void rtas_quiesce(PowerPCCPU *cpu, sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) { diff --git a/hw/ppc/xics.c b/hw/ppc/xics.c index 1b25075d14..091912e2ca 100644 --- a/hw/ppc/xics.c +++ b/hw/ppc/xics.c @@ -400,7 +400,8 @@ static target_ulong h_eoi(PowerPCCPU *cpu, sPAPREnvironment *spapr, return H_SUCCESS; } -static void rtas_set_xive(sPAPREnvironment *spapr, uint32_t token, +static void rtas_set_xive(PowerPCCPU *cpu, sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) { @@ -427,7 +428,8 @@ static void rtas_set_xive(sPAPREnvironment *spapr, uint32_t token, rtas_st(rets, 0, 0); /* Success */ } -static void rtas_get_xive(sPAPREnvironment *spapr, uint32_t token, +static void rtas_get_xive(PowerPCCPU *cpu, sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) { @@ -451,7 +453,8 @@ static void rtas_get_xive(sPAPREnvironment *spapr, uint32_t token, rtas_st(rets, 2, ics->irqs[nr - ics->offset].priority); } -static void rtas_int_off(sPAPREnvironment *spapr, uint32_t token, +static void rtas_int_off(PowerPCCPU *cpu, sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) { @@ -476,7 +479,8 @@ static void rtas_int_off(sPAPREnvironment *spapr, uint32_t token, rtas_st(rets, 0, 0); /* Success */ } -static void rtas_int_on(sPAPREnvironment *spapr, uint32_t token, +static void rtas_int_on(PowerPCCPU *cpu, sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) { diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index a83720ee65..09c4570982 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -319,11 +319,12 @@ static inline void rtas_st(target_ulong phys, int n, uint32_t val) stl_be_phys(phys + 4*n, val); } -typedef void (*spapr_rtas_fn)(sPAPREnvironment *spapr, uint32_t token, +typedef void (*spapr_rtas_fn)(PowerPCCPU *cpu, sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets); int spapr_rtas_register(const char *name, spapr_rtas_fn fn); -target_ulong spapr_rtas_call(sPAPREnvironment *spapr, +target_ulong spapr_rtas_call(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t token, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets); int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr, From ec4936e1a49ef2d7129a1813ed7a3ca826698bfb Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Wed, 19 Jun 2013 23:08:29 +0200 Subject: [PATCH 19/32] pseries: Fix compiler warning (conversion of pointer to integral value) This kind of type cast must use uintptr_t or target_ulong to be portable for hosts with sizeof(void *) != sizeof(long). Here the value is assigned to a variable of type target_ulong. Signed-off-by: Stefan Weil [agraf: fix compilation on 32bit hosts] Signed-off-by: Alexander Graf --- hw/ppc/spapr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 5363c3fe2c..fe34291ffd 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -670,7 +670,7 @@ static void spapr_cpu_reset(void *opaque) env->external_htab = spapr->htab; env->htab_base = -1; env->htab_mask = HTAB_SIZE(spapr) - 1; - env->spr[SPR_SDR1] = (unsigned long)spapr->htab | + env->spr[SPR_SDR1] = (target_ulong)(uintptr_t)spapr->htab | (spapr->htab_shift - 18); } From 4bddaf552c3a05e1fdd2c82d6b28ebc8f99269c9 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Sat, 15 Jun 2013 11:51:51 +1000 Subject: [PATCH 20/32] target-ppc kvm: save cr register This adds a missing code to save CR (condition register) via kvm_arch_put_registers(). kvm_arch_get_registers() already has it. Signed-off-by: Alexey Kardashevskiy Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/kvm.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 2bbc3b81dd..c89dd5827b 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -791,6 +791,11 @@ int kvm_arch_put_registers(CPUState *cs, int level) for (i = 0;i < 32; i++) regs.gpr[i] = env->gpr[i]; + regs.cr = 0; + for (i = 0; i < 8; i++) { + regs.cr |= (env->crf[i] & 15) << (4 * (7 - i)); + } + ret = kvm_vcpu_ioctl(cs, KVM_SET_REGS, ®s); if (ret < 0) return ret; From f9de2da728d885c5c246d6ba94edea067ad00434 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Sat, 15 Jun 2013 11:51:52 +1000 Subject: [PATCH 21/32] pseries: Update MAINTAINERS information I'm no longer at IBM, and therefore no long actively working on the pseries (aka sPAPR) qemu machine type. This patch removes my information in the MAINTAINERS file. While we're at it, I've added some extra file patterns for pseries specific files that weren't included in the existing pattern. Signed-off-by: David Gibson [agraf: Remove new maintainer addition] Signed-off-by: Alexander Graf --- MAINTAINERS | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index a015f68123..ad9c8602ea 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -428,11 +428,14 @@ F: hw/pci/devices/host-prep.[hc] F: hw/isa/pc87312.[hc] sPAPR -M: David Gibson M: Alexander Graf L: qemu-ppc@nongnu.org S: Supported F: hw/*/spapr* +F: include/hw/*/spapr* +F: hw/*/xics* +F: include/hw/*/xics* +F: pc-bios/spapr-rtas/* virtex_ml507 M: Edgar E. Iglesias From f1ff0e89c8287de79c804ec7a50d43f39a9f65dc Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 20 Jun 2013 14:06:27 +0200 Subject: [PATCH 22/32] Graphics: Switch to 800x600x32 as default mode We have stayed at 800x600x15 as default graphics mode for the last 9 years. If there ever was a reason to be there, surely nobody remembers it. However, recently non-Linux PPC guests started to show bad effects on 15 bit color mode. They do work just fine with 32 bits however. So let's switch to 32 bit color as the default graphic mode. Reported-by: Mark Cave-Ayland Signed-off-by: Alexander Graf --- arch_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch_init.c b/arch_init.c index 4255db98f7..0e553c9285 100644 --- a/arch_init.c +++ b/arch_init.c @@ -65,7 +65,7 @@ int graphic_depth = 8; #else int graphic_width = 800; int graphic_height = 600; -int graphic_depth = 15; +int graphic_depth = 32; #endif From ab8131afee34d6aa427bd56ac18c4d3b6df80728 Mon Sep 17 00:00:00 2001 From: Bharat Bhushan Date: Wed, 12 Jun 2013 18:00:50 +0530 Subject: [PATCH 23/32] booke_ppc: limit booke timer to max when timeout overflow Limit watchdog and fit timer to maximum timeout value which qemu timer can support (INT64_MAX). This maximum timeout will be hundreds of years, so limiting to max timeout is pretty safe. Signed-off-by: Bharat Bhushan Signed-off-by: Alexander Graf --- hw/ppc/ppc_booke.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/hw/ppc/ppc_booke.c b/hw/ppc/ppc_booke.c index e41b036b8e..000c27f2e8 100644 --- a/hw/ppc/ppc_booke.c +++ b/hw/ppc/ppc_booke.c @@ -131,17 +131,33 @@ static void booke_update_fixed_timer(CPUPPCState *env, struct QEMUTimer *timer) { ppc_tb_t *tb_env = env->tb_env; - uint64_t lapse; + uint64_t delta_tick, ticks = 0; uint64_t tb; - uint64_t period = 1 << (target_bit + 1); + uint64_t period; uint64_t now; now = qemu_get_clock_ns(vm_clock); tb = cpu_ppc_get_tb(tb_env, now, tb_env->tb_offset); + period = 1ULL << target_bit; + delta_tick = period - (tb & (period - 1)); - lapse = period - ((tb - (1 << target_bit)) & (period - 1)); + /* the timer triggers only when the selected bit toggles from 0 to 1 */ + if (tb & period) { + ticks = period; + } - *next = now + muldiv64(lapse, get_ticks_per_sec(), tb_env->tb_freq); + if (ticks + delta_tick < ticks) { + /* Overflow, so assume the biggest number we can express. */ + ticks = UINT64_MAX; + } else { + ticks += delta_tick; + } + + *next = now + muldiv64(ticks, get_ticks_per_sec(), tb_env->tb_freq); + if ((*next < now) || (*next > INT64_MAX)) { + /* Overflow, so assume the biggest number the qemu timer supports. */ + *next = INT64_MAX; + } /* XXX: If expire time is now. We can't run the callback because we don't * have access to it. So we just set the timer one nanosecond later. From b048960f15dbedeceb4e1d7e469080cf68d4cf67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 9 Jun 2013 22:11:49 +0200 Subject: [PATCH 24/32] target-ppc: Introduce unrealizefn for PowerPCCPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use it to clean up the opcode table, resolving a former TODO from Jocelyn. Also switch from malloc() to g_malloc(). Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/cpu.h | 4 +++- target-ppc/translate_init.c | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index aa1d013c31..0ede077d72 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -886,6 +886,8 @@ struct ppc_segment_page_sizes { /* The whole PowerPC CPU context */ #define NB_MMU_MODES 3 +#define PPC_CPU_OPCODES_LEN 0x40 + struct CPUPPCState { /* First are the most commonly used resources * during translated code execution @@ -1039,7 +1041,7 @@ struct CPUPPCState { /* Those resources are used only during code translation */ /* opcode handlers */ - opc_handler_t *opcodes[0x40]; + opc_handler_t *opcodes[PPC_CPU_OPCODES_LEN]; /* Those resources are used only in QEMU core */ target_ulong hflags; /* hflags is a MSR & HFLAGS_MASK */ diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index f365ad833c..f01e9e7d91 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7256,7 +7256,7 @@ static int create_new_table (opc_handler_t **table, unsigned char idx) { opc_handler_t **tmp; - tmp = malloc(0x20 * sizeof(opc_handler_t)); + tmp = g_malloc(0x20 * sizeof(opc_handler_t)); fill_new_table(tmp, 0x20); table[idx] = (opc_handler_t *)((uintptr_t)tmp | PPC_INDIRECT); @@ -7864,6 +7864,19 @@ static void ppc_cpu_realizefn(DeviceState *dev, Error **errp) #endif } +static void ppc_cpu_unrealizefn(DeviceState *dev, Error **errp) +{ + PowerPCCPU *cpu = POWERPC_CPU(dev); + CPUPPCState *env = &cpu->env; + int i; + + for (i = 0; i < PPC_CPU_OPCODES_LEN; i++) { + if (env->opcodes[i] != &invalid_handler) { + g_free(env->opcodes[i]); + } + } +} + static gint ppc_cpu_compare_class_pvr(gconstpointer a, gconstpointer b) { ObjectClass *oc = (ObjectClass *)a; @@ -8251,6 +8264,7 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data) pcc->parent_realize = dc->realize; dc->realize = ppc_cpu_realizefn; + dc->unrealize = ppc_cpu_unrealizefn; pcc->parent_reset = cc->reset; cc->reset = ppc_cpu_reset; From 886b75779104f38c30cc2594fcf2b214615a242d Mon Sep 17 00:00:00 2001 From: Fabien Chouteau Date: Fri, 21 Jun 2013 15:26:57 +0200 Subject: [PATCH 25/32] PPC: Add dump_mmu() for 6xx "(qemu) info tlb" is a very useful tool for debugging, so I implemented the missing 6xx version. Signed-off-by: Fabien Chouteau [agraf: fix printfs on hwaddr to PRI] Signed-off-by: Alexander Graf --- target-ppc/mmu_helper.c | 92 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c index 68d5415e54..34330dc7d6 100644 --- a/target-ppc/mmu_helper.c +++ b/target-ppc/mmu_helper.c @@ -1176,6 +1176,94 @@ static void mmubooke206_dump_mmu(FILE *f, fprintf_function cpu_fprintf, } } +static void mmu6xx_dump_BATs(FILE *f, fprintf_function cpu_fprintf, + CPUPPCState *env, int type) +{ + target_ulong *BATlt, *BATut, *BATu, *BATl; + target_ulong BEPIl, BEPIu, bl; + int i; + + switch (type) { + case ACCESS_CODE: + BATlt = env->IBAT[1]; + BATut = env->IBAT[0]; + break; + default: + BATlt = env->DBAT[1]; + BATut = env->DBAT[0]; + break; + } + + for (i = 0; i < env->nb_BATs; i++) { + BATu = &BATut[i]; + BATl = &BATlt[i]; + BEPIu = *BATu & 0xF0000000; + BEPIl = *BATu & 0x0FFE0000; + bl = (*BATu & 0x00001FFC) << 15; + cpu_fprintf(f, "%s BAT%d BATu " TARGET_FMT_lx + " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " " + TARGET_FMT_lx " " TARGET_FMT_lx "\n", + type == ACCESS_CODE ? "code" : "data", i, + *BATu, *BATl, BEPIu, BEPIl, bl); + } +} + +static void mmu6xx_dump_mmu(FILE *f, fprintf_function cpu_fprintf, + CPUPPCState *env) +{ + ppc6xx_tlb_t *tlb; + target_ulong sr; + int type, way, entry, i; + + cpu_fprintf(f, "HTAB base = 0x%"HWADDR_PRIx"\n", env->htab_base); + cpu_fprintf(f, "HTAB mask = 0x%"HWADDR_PRIx"\n", env->htab_mask); + + cpu_fprintf(f, "\nSegment registers:\n"); + for (i = 0; i < 32; i++) { + sr = env->sr[i]; + if (sr & 0x80000000) { + cpu_fprintf(f, "%02d T=%d Ks=%d Kp=%d BUID=0x%03x " + "CNTLR_SPEC=0x%05x\n", i, + sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0, + sr & 0x20000000 ? 1 : 0, (uint32_t)((sr >> 20) & 0x1FF), + (uint32_t)(sr & 0xFFFFF)); + } else { + cpu_fprintf(f, "%02d T=%d Ks=%d Kp=%d N=%d VSID=0x%06x\n", i, + sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0, + sr & 0x20000000 ? 1 : 0, sr & 0x10000000 ? 1 : 0, + (uint32_t)(sr & 0x00FFFFFF)); + } + } + + cpu_fprintf(f, "\nBATs:\n"); + mmu6xx_dump_BATs(f, cpu_fprintf, env, ACCESS_INT); + mmu6xx_dump_BATs(f, cpu_fprintf, env, ACCESS_CODE); + + if (env->id_tlbs != 1) { + cpu_fprintf(f, "ERROR: 6xx MMU should have separated TLB" + " for code and data\n"); + } + + cpu_fprintf(f, "\nTLBs [EPN EPN + SIZE]\n"); + + for (type = 0; type < 2; type++) { + for (way = 0; way < env->nb_ways; way++) { + for (entry = env->nb_tlb * type + env->tlb_per_way * way; + entry < (env->nb_tlb * type + env->tlb_per_way * (way + 1)); + entry++) { + + tlb = &env->tlb.tlb6[entry]; + cpu_fprintf(f, "%s TLB %02d/%02d way:%d %s [" + TARGET_FMT_lx " " TARGET_FMT_lx "]\n", + type ? "code" : "data", entry % env->nb_tlb, + env->nb_tlb, way, + pte_is_valid(tlb->pte0) ? "valid" : "inval", + tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE); + } + } + } +} + void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env) { switch (env->mmu_model) { @@ -1185,6 +1273,10 @@ void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env) case POWERPC_MMU_BOOKE206: mmubooke206_dump_mmu(f, cpu_fprintf, env); break; + case POWERPC_MMU_SOFT_6xx: + case POWERPC_MMU_SOFT_74xx: + mmu6xx_dump_mmu(f, cpu_fprintf, env); + break; #if defined(TARGET_PPC64) case POWERPC_MMU_64B: case POWERPC_MMU_2_06: From b177d8b77c7301da9b51b829b0edcff367e92023 Mon Sep 17 00:00:00 2001 From: Fabien Chouteau Date: Tue, 18 Jun 2013 16:53:01 +0200 Subject: [PATCH 26/32] PPC: Fix GDB read on code area for PPC6xx On PPC 6xx, data and code have separated TLBs. Until now QEMU was only looking at data TLBs, which is not good when GDB wants to read code. This patch adds a second call to get_physical_address() with an ACCESS_CODE type of access when the first call with ACCESS_INT fails. Signed-off-by: Fabien Chouteau Signed-off-by: Alexander Graf --- target-ppc/mmu_helper.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c index 34330dc7d6..385b67ab23 100644 --- a/target-ppc/mmu_helper.c +++ b/target-ppc/mmu_helper.c @@ -1431,7 +1431,15 @@ hwaddr cpu_get_phys_page_debug(CPUPPCState *env, target_ulong addr) } if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0)) { - return -1; + + /* Some MMUs have separate TLBs for code and data. If we only try an + * ACCESS_INT, we may not be able to read instructions mapped by code + * TLBs, so we also try a ACCESS_CODE. + */ + if (unlikely(get_physical_address(env, &ctx, addr, 0, + ACCESS_CODE) != 0)) { + return -1; + } } return ctx.raddr & TARGET_PAGE_MASK; From 9761ad757182be663fa31af99abad959ac63b17f Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Sat, 22 Jun 2013 03:53:35 +0200 Subject: [PATCH 27/32] PPC: Introduce an alias cache for faster lookups When running QEMU with "-cpu ?" we walk through every alias for every target CPU we know about. This takes several seconds on my very fast host system. Let's introduce a class object cache in the alias table. Using that we don't have to go through the tedious work of finding our target class. Instead, we can just go directly from the alias name to the target class pointer. This patch brings -cpu "?" to reasonable times again. Before: real 0m4.716s After: real 0m0.025s Signed-off-by: Alexander Graf --- target-ppc/cpu-models.c | 2 +- target-ppc/cpu-models.h | 3 ++- target-ppc/translate_init.c | 32 +++++++++++++++++++++++++++----- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/target-ppc/cpu-models.c b/target-ppc/cpu-models.c index 17f56b7504..9bb68c8191 100644 --- a/target-ppc/cpu-models.c +++ b/target-ppc/cpu-models.c @@ -1227,7 +1227,7 @@ /***************************************************************************/ /* PowerPC CPU aliases */ -const PowerPCCPUAlias ppc_cpu_aliases[] = { +PowerPCCPUAlias ppc_cpu_aliases[] = { { "403", "403GC" }, { "405", "405D4" }, { "405CR", "405CRc" }, diff --git a/target-ppc/cpu-models.h b/target-ppc/cpu-models.h index a94f835121..ae8f7c743e 100644 --- a/target-ppc/cpu-models.h +++ b/target-ppc/cpu-models.h @@ -31,9 +31,10 @@ typedef struct PowerPCCPUAlias { const char *alias; const char *model; + ObjectClass *oc; } PowerPCCPUAlias; -extern const PowerPCCPUAlias ppc_cpu_aliases[]; +extern PowerPCCPUAlias ppc_cpu_aliases[]; /*****************************************************************************/ /* PVR definitions for most known PowerPC */ diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index f01e9e7d91..937390a967 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7934,6 +7934,28 @@ static gint ppc_cpu_compare_class_name(gconstpointer a, gconstpointer b) #include +static ObjectClass *ppc_cpu_class_by_name(const char *name); + +static ObjectClass *ppc_cpu_class_by_alias(PowerPCCPUAlias *alias) +{ + ObjectClass *invalid_class = (void*)ppc_cpu_class_by_alias; + + /* Cache target class lookups in the alias table */ + if (!alias->oc) { + alias->oc = ppc_cpu_class_by_name(alias->model); + if (!alias->oc) { + /* Fast check for non-existing aliases */ + alias->oc = invalid_class; + } + } + + if (alias->oc == invalid_class) { + return NULL; + } else { + return alias->oc; + } +} + static ObjectClass *ppc_cpu_class_by_name(const char *name) { GSList *list, *item; @@ -7961,7 +7983,7 @@ static ObjectClass *ppc_cpu_class_by_name(const char *name) for (i = 0; ppc_cpu_aliases[i].alias != NULL; i++) { if (strcmp(ppc_cpu_aliases[i].alias, name) == 0) { - return ppc_cpu_class_by_name(ppc_cpu_aliases[i].model); + return ppc_cpu_class_by_alias(&ppc_cpu_aliases[i]); } } @@ -8051,8 +8073,8 @@ static void ppc_cpu_list_entry(gpointer data, gpointer user_data) (*s->cpu_fprintf)(s->file, "PowerPC %-16s PVR %08x\n", name, pcc->pvr); for (i = 0; ppc_cpu_aliases[i].alias != NULL; i++) { - const PowerPCCPUAlias *alias = &ppc_cpu_aliases[i]; - ObjectClass *alias_oc = ppc_cpu_class_by_name(alias->model); + PowerPCCPUAlias *alias = &ppc_cpu_aliases[i]; + ObjectClass *alias_oc = ppc_cpu_class_by_alias(alias); if (alias_oc != oc) { continue; @@ -8119,12 +8141,12 @@ CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp) g_slist_free(list); for (i = 0; ppc_cpu_aliases[i].alias != NULL; i++) { - const PowerPCCPUAlias *alias = &ppc_cpu_aliases[i]; + PowerPCCPUAlias *alias = &ppc_cpu_aliases[i]; ObjectClass *oc; CpuDefinitionInfoList *entry; CpuDefinitionInfo *info; - oc = ppc_cpu_class_by_name(alias->model); + oc = ppc_cpu_class_by_alias(alias); if (oc == NULL) { continue; } From a1014f25ef54bbbdaf571873a1254f85d6dcf132 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Sun, 23 Jun 2013 00:22:50 +0200 Subject: [PATCH 28/32] PPC: Add clock-frequency export for Mac machines Support in fwcfg has been around for exposure of the clock-frequency CPU property. OpenBIOS reads it, we just never exposed it. Since Mac OS X is very picky about its clock frequency values, let's just take a known good value and always expose that. Reported-by: Mark Cave-Ayland Signed-off-by: Alexander Graf --- hw/ppc/mac_newworld.c | 2 ++ hw/ppc/mac_oldworld.c | 2 ++ include/hw/ppc/ppc.h | 1 + 3 files changed, 5 insertions(+) diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index d8e4db3b6a..c6889d1055 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -449,6 +449,8 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) } else { fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, get_ticks_per_sec()); } + /* Mac OS X requires a "known good" clock-frequency value; pass it one. */ + fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_CLOCKFREQ, 266000000); qemu_register_boot_set(fw_cfg_boot_set, fw_cfg); } diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index 3acca94432..8faff300ff 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -333,6 +333,8 @@ static void ppc_heathrow_init(QEMUMachineInitArgs *args) } else { fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, get_ticks_per_sec()); } + /* Mac OS X requires a "known good" clock-frequency value; pass it one. */ + fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_CLOCKFREQ, 266000000); qemu_register_boot_set(fw_cfg_boot_set, fw_cfg); } diff --git a/include/hw/ppc/ppc.h b/include/hw/ppc/ppc.h index acaf0d6580..dfcad259b2 100644 --- a/include/hw/ppc/ppc.h +++ b/include/hw/ppc/ppc.h @@ -87,6 +87,7 @@ enum { #define FW_CFG_PPC_HEIGHT (FW_CFG_ARCH_LOCAL + 0x01) #define FW_CFG_PPC_DEPTH (FW_CFG_ARCH_LOCAL + 0x02) #define FW_CFG_PPC_TBFREQ (FW_CFG_ARCH_LOCAL + 0x03) +#define FW_CFG_PPC_CLOCKFREQ (FW_CFG_ARCH_LOCAL + 0x04) #define FW_CFG_PPC_IS_KVM (FW_CFG_ARCH_LOCAL + 0x05) #define FW_CFG_PPC_KVM_HC (FW_CFG_ARCH_LOCAL + 0x06) #define FW_CFG_PPC_KVM_PID (FW_CFG_ARCH_LOCAL + 0x07) From 4e46dcdbd31314c66fc19f73d9358852f77e8e2e Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 25 Jun 2013 03:39:21 +0200 Subject: [PATCH 29/32] PPC: Newworld: Add uninorth token register Mac OS X expects the uninorth control register set to contain one register that always reads back what it writes in. Expose that. This is just a temporary hack. Eventually, we want to expose the uninorth (/uni-n in device tree) as a separate QOM device. Signed-off-by: Alexander Graf --- hw/ppc/mac_newworld.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index c6889d1055..7b512cae19 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -87,6 +87,9 @@ static void unin_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { UNIN_DPRINTF("write addr " TARGET_FMT_plx " val %"PRIx64"\n", addr, value); + if (addr == 0x0) { + *(int*)opaque = value; + } } static uint64_t unin_read(void *opaque, hwaddr addr, unsigned size) @@ -94,6 +97,11 @@ static uint64_t unin_read(void *opaque, hwaddr addr, unsigned size) uint32_t value; value = 0; + switch (addr) { + case 0: + value = *(int*)opaque; + } + UNIN_DPRINTF("readl addr " TARGET_FMT_plx " val %x\n", addr, value); return value; @@ -162,6 +170,7 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) int machine_arch; SysBusDevice *s; DeviceState *dev; + int *token = g_new(int, 1); linux_boot = (kernel_filename != NULL); @@ -279,8 +288,8 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) /* Register 8 MB of ISA IO space */ isa_mmio_init(0xf2000000, 0x00800000); - /* UniN init */ - memory_region_init_io(unin_memory, &unin_ops, NULL, "unin", 0x1000); + /* UniN init: XXX should be a real device */ + memory_region_init_io(unin_memory, &unin_ops, token, "unin", 0x1000); memory_region_add_subregion(get_system_memory(), 0xf8000000, unin_memory); openpic_irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *)); From 593c18116090237db96af6e50b902d790265ebc5 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 25 Jun 2013 03:46:33 +0200 Subject: [PATCH 30/32] PPC: Newworld: Add second uninorth control register set Mac OS X requires a second uninorth register set to be mapped a few bytes above the first one. Let's just expose it to make it happy. Signed-off-by: Alexander Graf --- hw/ppc/mac_newworld.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 7b512cae19..3badfa3adb 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -152,6 +152,7 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) char *filename; qemu_irq *pic, **openpic_irqs; MemoryRegion *unin_memory = g_new(MemoryRegion, 1); + MemoryRegion *unin2_memory = g_new(MemoryRegion, 1); int linux_boot, i, j, k; MemoryRegion *ram = g_new(MemoryRegion, 1), *bios = g_new(MemoryRegion, 1); hwaddr kernel_base, initrd_base, cmdline_base = 0; @@ -292,6 +293,9 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) memory_region_init_io(unin_memory, &unin_ops, token, "unin", 0x1000); memory_region_add_subregion(get_system_memory(), 0xf8000000, unin_memory); + memory_region_init_io(unin2_memory, &unin_ops, token, "unin", 0x1000); + memory_region_add_subregion(get_system_memory(), 0xf3000000, unin2_memory); + openpic_irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *)); openpic_irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB); From 0d54a5024f846ce7d53db25012fb4c7481e971ff Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 26 Jun 2013 13:58:31 +0200 Subject: [PATCH 31/32] mac-io: Add escc-legacy memory alias region Mac OS X's debugging serial driver accesses the ESCC through a different register layout, called "escc-legacy". This layout differs from the normal escc register layout purely by the location of the respective registers. This patch adds a memory alias region that takes normal escc registers and maps them into the escc-legacy register space. With this patch applied, a Mac OS X guest successfully emits debug output on the serial port when run with debug parameters set, for example by running: $ qemu-system-ppc -prom-env -'boot-args=-v debug=0x8 io=0xff serial=0x3' \ -cdrom 10.4.iso -boot d Signed-off-by: Alexander Graf --- hw/misc/macio/macio.c | 47 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c index 2f389dd7cc..fd4c8e5f99 100644 --- a/hw/misc/macio/macio.c +++ b/hw/misc/macio/macio.c @@ -69,12 +69,59 @@ typedef struct NewWorldMacIOState { MACIOIDEState ide[2]; } NewWorldMacIOState; +/* + * The mac-io has two interfaces to the ESCC. One is called "escc-legacy", + * while the other one is the normal, current ESCC interface. + * + * The magic below creates memory aliases to spawn the escc-legacy device + * purely by rerouting the respective registers to our escc region. This + * works because the only difference between the two memory regions is the + * register layout, not their semantics. + * + * Reference: ftp://ftp.software.ibm.com/rs6000/technology/spec/chrp/inwork/CHRP_IORef_1.0.pdf + */ +static void macio_escc_legacy_setup(MacIOState *macio_state) +{ + MemoryRegion *escc_legacy = g_new(MemoryRegion, 1); + MemoryRegion *bar = &macio_state->bar; + int i; + static const int maps[] = { + 0x00, 0x00, + 0x02, 0x20, + 0x04, 0x10, + 0x06, 0x30, + 0x08, 0x40, + 0x0A, 0x50, + 0x60, 0x60, + 0x70, 0x70, + 0x80, 0x70, + 0x90, 0x80, + 0xA0, 0x90, + 0xB0, 0xA0, + 0xC0, 0xB0, + 0xD0, 0xC0, + 0xE0, 0xD0, + 0xF0, 0xE0, + }; + + memory_region_init(escc_legacy, "escc-legacy", 256); + for (i = 0; i < ARRAY_SIZE(maps); i += 2) { + MemoryRegion *port = g_new(MemoryRegion, 1); + memory_region_init_alias(port, "escc-legacy-port", macio_state->escc_mem, + maps[i+1], 0x2); + memory_region_add_subregion(escc_legacy, maps[i], port); + } + + memory_region_add_subregion(bar, 0x12000, escc_legacy); +} + static void macio_bar_setup(MacIOState *macio_state) { MemoryRegion *bar = &macio_state->bar; if (macio_state->escc_mem) { memory_region_add_subregion(bar, 0x13000, macio_state->escc_mem); + macio_escc_legacy_setup(macio_state); } } From 2345f1c0146672ce6eb0025bd2cfa4afabdef5fd Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 27 Jun 2013 00:31:42 +0200 Subject: [PATCH 32/32] PPC: Ignore writes to L2CR The L2CR register contains a number of bits that either impose configuration which we can't deal with or mean "something is in progress until the bit is 0 again". Since we don't model the former and we do want to accomodate guests using the latter semantics, let's just ignore writes to L2CR. That way guests always read back 0 and are usually happy with that. Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 937390a967..50e0ee5735 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -1381,7 +1381,7 @@ static void gen_spr_74xx (CPUPPCState *env) /* XXX : not implemented */ spr_register(env, SPR_L2CR, "L2CR", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, NULL, 0x00000000); /* Not strictly an SPR */ vscr_init(env, 0x00010000); @@ -5169,7 +5169,7 @@ static void init_proc_750 (CPUPPCState *env) /* XXX : not implemented */ spr_register(env, SPR_L2CR, "L2CR", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, NULL, 0x00000000); /* Time base */ gen_tbl(env); @@ -5232,7 +5232,7 @@ static void init_proc_750cl (CPUPPCState *env) /* XXX : not implemented */ spr_register(env, SPR_L2CR, "L2CR", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, NULL, 0x00000000); /* Time base */ gen_tbl(env); @@ -5418,7 +5418,7 @@ static void init_proc_750cx (CPUPPCState *env) /* XXX : not implemented */ spr_register(env, SPR_L2CR, "L2CR", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, NULL, 0x00000000); /* Time base */ gen_tbl(env); @@ -5485,7 +5485,7 @@ static void init_proc_750fx (CPUPPCState *env) /* XXX : not implemented */ spr_register(env, SPR_L2CR, "L2CR", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, NULL, 0x00000000); /* Time base */ gen_tbl(env); @@ -5557,7 +5557,7 @@ static void init_proc_750gx (CPUPPCState *env) /* XXX : not implemented (XXX: different from 750fx) */ spr_register(env, SPR_L2CR, "L2CR", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, NULL, 0x00000000); /* Time base */ gen_tbl(env); @@ -5693,7 +5693,7 @@ static void init_proc_755 (CPUPPCState *env) /* XXX : not implemented */ spr_register(env, SPR_L2CR, "L2CR", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, NULL, 0x00000000); /* XXX : not implemented */ spr_register(env, SPR_L2PMCR, "L2PMCR", @@ -6524,7 +6524,7 @@ static void init_proc_970 (CPUPPCState *env) /* XXX : not implemented */ spr_register(env, SPR_L2CR, "L2CR", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, NULL, 0x00000000); /* Memory management */ /* XXX: not correct */ @@ -6624,7 +6624,7 @@ static void init_proc_970FX (CPUPPCState *env) /* XXX : not implemented */ spr_register(env, SPR_L2CR, "L2CR", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, NULL, 0x00000000); /* Memory management */ /* XXX: not correct */ @@ -6736,7 +6736,7 @@ static void init_proc_970GX (CPUPPCState *env) /* XXX : not implemented */ spr_register(env, SPR_L2CR, "L2CR", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, NULL, 0x00000000); /* Memory management */ /* XXX: not correct */ @@ -6836,7 +6836,7 @@ static void init_proc_970MP (CPUPPCState *env) /* XXX : not implemented */ spr_register(env, SPR_L2CR, "L2CR", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, NULL, 0x00000000); /* Memory management */ /* XXX: not correct */