From 52d631dcc70144b6ce8293db78cd6de635331c83 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> Date: Tue, 27 Mar 2012 16:41:55 +0100 Subject: PPC: Fix TLB invalidation bug within the PPC interrupt handler. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 41557447d30eeb944e42069513df13585f5e6c7f also introduced a subtle TLB flush bug. By applying a mask to the interrupt MSR which cleared the IR/DR bits at the start of the interrupt handler, the logic towards the end of the handler to force a TLB flush if either one of these bits were set would never be triggered. This patch simply changes the IR/DR bit check in the TLB flush logic to use the original MSR value (albeit with some interrupt-specific bits cleared) so that the IR/DR bits are preserved at the point where the check takes place. Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> Acked-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Andreas Färber <afaerber@suse.de> --- target-ppc/helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index e13b749..f0ea1c3 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -2960,7 +2960,7 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp) if (asrr1 != -1) env->spr[asrr1] = env->spr[srr1]; /* If we disactivated any translation, flush TLBs */ - if (new_msr & ((1 << MSR_IR) | (1 << MSR_DR))) + if (msr & ((1 << MSR_IR) | (1 << MSR_DR))) tlb_flush(env, 1); if (msr_ile) { -- cgit v1.1 From d9599c9205089805cd6ef55985beeb06aef0c819 Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Thu, 29 Mar 2012 08:39:45 +1100 Subject: pseries: Clean up hcall_dprintf() debugging messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pseries machine code has a number of debug messages for debugging PAPR hypercalls, dependent on DEBUG_SPAPR_HCALLS. This patch cleans these messages up a bit, by adding __func__ to the hcall_dprintf() macro and simplifying up a number of the individual messages accordingly. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Andreas Färber <afaerber@suse.de> --- hw/spapr.h | 2 +- hw/spapr_llan.c | 12 +++++------- hw/spapr_vio.c | 25 +++++++++---------------- 3 files changed, 15 insertions(+), 24 deletions(-) diff --git a/hw/spapr.h b/hw/spapr.h index 11160b0..654a7a8 100644 --- a/hw/spapr.h +++ b/hw/spapr.h @@ -272,7 +272,7 @@ extern sPAPREnvironment *spapr; #ifdef DEBUG_SPAPR_HCALLS #define hcall_dprintf(fmt, ...) \ - do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) + do { fprintf(stderr, "%s: " fmt, __func__, ## __VA_ARGS__); } while (0) #else #define hcall_dprintf(fmt, ...) \ do { } while (0) diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c index cfc7778..32dce17 100644 --- a/hw/spapr_llan.c +++ b/hw/spapr_llan.c @@ -279,21 +279,19 @@ static target_ulong h_register_logical_lan(CPUPPCState *env, if (check_bd(dev, VLAN_VALID_BD(buf_list, SPAPR_VIO_TCE_PAGE_SIZE), SPAPR_VIO_TCE_PAGE_SIZE) < 0) { - hcall_dprintf("Bad buf_list 0x" TARGET_FMT_lx " for " - "H_REGISTER_LOGICAL_LAN\n", buf_list); + hcall_dprintf("Bad buf_list 0x" TARGET_FMT_lx "\n", buf_list); return H_PARAMETER; } filter_list_bd = VLAN_VALID_BD(filter_list, SPAPR_VIO_TCE_PAGE_SIZE); if (check_bd(dev, filter_list_bd, SPAPR_VIO_TCE_PAGE_SIZE) < 0) { - hcall_dprintf("Bad filter_list 0x" TARGET_FMT_lx " for " - "H_REGISTER_LOGICAL_LAN\n", filter_list); + hcall_dprintf("Bad filter_list 0x" TARGET_FMT_lx "\n", filter_list); return H_PARAMETER; } if (!(rec_queue & VLAN_BD_VALID) || (check_bd(dev, rec_queue, VLAN_RQ_ALIGNMENT) < 0)) { - hcall_dprintf("Bad receive queue for H_REGISTER_LOGICAL_LAN\n"); + hcall_dprintf("Bad receive queue\n"); return H_PARAMETER; } @@ -358,13 +356,13 @@ static target_ulong h_add_logical_lan_buffer(CPUPPCState *env, ", 0x" TARGET_FMT_lx ")\n", reg, buf); if (!sdev) { - hcall_dprintf("Wrong device in h_add_logical_lan_buffer\n"); + hcall_dprintf("Bad device\n"); return H_PARAMETER; } if ((check_bd(dev, buf, 4) < 0) || (VLAN_BD_LEN(buf) < 16)) { - hcall_dprintf("Bad buffer enqueued in h_add_logical_lan_buffer\n"); + hcall_dprintf("Bad buffer enqueued\n"); return H_PARAMETER; } diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index dbf5a90..1f67e64 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -204,8 +204,7 @@ static target_ulong h_put_tce(CPUPPCState *env, sPAPREnvironment *spapr, VIOsPAPR_RTCE *rtce; if (!dev) { - hcall_dprintf("spapr_vio_put_tce on non-existent LIOBN " - TARGET_FMT_lx "\n", liobn); + hcall_dprintf("LIOBN 0x" TARGET_FMT_lx " does not exist\n", liobn); return H_PARAMETER; } @@ -217,8 +216,7 @@ static target_ulong h_put_tce(CPUPPCState *env, sPAPREnvironment *spapr, #endif if (ioba >= dev->rtce_window_size) { - hcall_dprintf("spapr_vio_put_tce on out-of-boards IOBA 0x" - TARGET_FMT_lx "\n", ioba); + hcall_dprintf("Out-of-bounds IOBA 0x" TARGET_FMT_lx "\n", ioba); return H_PARAMETER; } @@ -414,22 +412,20 @@ static target_ulong h_reg_crq(CPUPPCState *env, sPAPREnvironment *spapr, VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); if (!dev) { - hcall_dprintf("h_reg_crq on non-existent unit 0x" - TARGET_FMT_lx "\n", reg); + hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg); return H_PARAMETER; } /* We can't grok a queue size bigger than 256M for now */ if (queue_len < 0x1000 || queue_len > 0x10000000) { - hcall_dprintf("h_reg_crq, queue size too small or too big (0x%llx)\n", - (unsigned long long)queue_len); + hcall_dprintf("Queue size too small or too big (0x" TARGET_FMT_lx + ")\n", queue_len); return H_PARAMETER; } /* Check queue alignment */ if (queue_addr & 0xfff) { - hcall_dprintf("h_reg_crq, queue not aligned (0x%llx)\n", - (unsigned long long)queue_addr); + hcall_dprintf("Queue not aligned (0x" TARGET_FMT_lx ")\n", queue_addr); return H_PARAMETER; } @@ -460,8 +456,7 @@ static target_ulong h_free_crq(CPUPPCState *env, sPAPREnvironment *spapr, VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); if (!dev) { - hcall_dprintf("h_free_crq on non-existent unit 0x" - TARGET_FMT_lx "\n", reg); + hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg); return H_PARAMETER; } @@ -484,8 +479,7 @@ static target_ulong h_send_crq(CPUPPCState *env, sPAPREnvironment *spapr, uint64_t crq_mangle[2]; if (!dev) { - hcall_dprintf("h_send_crq on non-existent unit 0x" - TARGET_FMT_lx "\n", reg); + hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg); return H_PARAMETER; } crq_mangle[0] = cpu_to_be64(msg_hi); @@ -505,8 +499,7 @@ static target_ulong h_enable_crq(CPUPPCState *env, sPAPREnvironment *spapr, VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); if (!dev) { - hcall_dprintf("h_enable_crq on non-existent unit 0x" - TARGET_FMT_lx "\n", reg); + hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg); return H_PARAMETER; } -- cgit v1.1 From 8e01f355db4c7e54b0877a6d9508e83d0afbc4b6 Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Thu, 29 Mar 2012 08:39:46 +1100 Subject: pseries: Fix bug with reset of VIO CRQs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PAPR specifies a Command Response Queue (CRQ) mechanism used for virtual IO, which we implement. However, we don't correctly clean up registered CRQs when we reset the system. This patch adds a reset handler to fix this bug. While we're at it, add in some of the extra debug messages that were used to track the problem down. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> [AF: Updated hcall_dprintf()s to not duplicate the function name] Signed-off-by: Andreas Färber <afaerber@suse.de> --- hw/spapr_vio.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index 1f67e64..0bf2c31 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -431,12 +431,13 @@ static target_ulong h_reg_crq(CPUPPCState *env, sPAPREnvironment *spapr, /* Check if device supports CRQs */ if (!dev->crq.SendFunc) { + hcall_dprintf("Device does not support CRQ\n"); return H_NOT_FOUND; } - /* Already a queue ? */ if (dev->crq.qsize) { + hcall_dprintf("CRQ already registered\n"); return H_RESOURCE; } dev->crq.qladdr = queue_addr; @@ -449,6 +450,17 @@ static target_ulong h_reg_crq(CPUPPCState *env, sPAPREnvironment *spapr, return H_SUCCESS; } +static target_ulong free_crq(VIOsPAPRDevice *dev) +{ + dev->crq.qladdr = 0; + dev->crq.qsize = 0; + dev->crq.qnext = 0; + + dprintf("CRQ for dev 0x%" PRIx32 " freed\n", dev->reg); + + return H_SUCCESS; +} + static target_ulong h_free_crq(CPUPPCState *env, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { @@ -460,13 +472,7 @@ static target_ulong h_free_crq(CPUPPCState *env, sPAPREnvironment *spapr, return H_PARAMETER; } - dev->crq.qladdr = 0; - dev->crq.qsize = 0; - dev->crq.qnext = 0; - - dprintf("CRQ for dev 0x" TARGET_FMT_lx " freed\n", reg); - - return H_SUCCESS; + return free_crq(dev); } static target_ulong h_send_crq(CPUPPCState *env, sPAPREnvironment *spapr, @@ -642,6 +648,15 @@ static int spapr_vio_check_reg(VIOsPAPRDevice *sdev) return 0; } +static void spapr_vio_busdev_reset(void *opaque) +{ + VIOsPAPRDevice *dev = (VIOsPAPRDevice *)opaque; + + if (dev->crq.qsize) { + free_crq(dev); + } +} + static int spapr_vio_busdev_init(DeviceState *qdev) { VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev; @@ -670,6 +685,8 @@ static int spapr_vio_busdev_init(DeviceState *qdev) rtce_init(dev); + qemu_register_reset(spapr_vio_busdev_reset, dev); + return pc->init(dev); } -- cgit v1.1 From c821a43c60e55fdfb8bc9c64696238e409d96192 Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Thu, 29 Mar 2012 08:39:47 +1100 Subject: pseries: Implement RTAS system-reboot call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds the PAPR defined RTAS system-reboot call to the pseries machine emulation, providing the guest with a way to trigger a reboot. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Andreas Färber <afaerber@suse.de> --- hw/spapr_rtas.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/hw/spapr_rtas.c b/hw/spapr_rtas.c index 0946585..480a4ae 100644 --- a/hw/spapr_rtas.c +++ b/hw/spapr_rtas.c @@ -112,6 +112,19 @@ static void rtas_power_off(sPAPREnvironment *spapr, rtas_st(rets, 0, 0); } +static void rtas_system_reboot(sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, + target_ulong args, + uint32_t nret, target_ulong rets) +{ + if (nargs != 0 || nret != 1) { + rtas_st(rets, 0, -3); + return; + } + qemu_system_reset_request(); + rtas_st(rets, 0, 0); +} + static void rtas_query_cpu_stopped_state(sPAPREnvironment *spapr, uint32_t token, uint32_t nargs, target_ulong args, @@ -294,6 +307,7 @@ static void core_rtas_register_types(void) spapr_rtas_register("get-time-of-day", rtas_get_time_of_day); spapr_rtas_register("set-time-of-day", rtas_set_time_of_day); spapr_rtas_register("power-off", rtas_power_off); + spapr_rtas_register("system-reboot", rtas_system_reboot); spapr_rtas_register("query-cpu-stopped-state", rtas_query_cpu_stopped_state); spapr_rtas_register("start-cpu", rtas_start_cpu); -- cgit v1.1 From 3b768df95a877577a9b8d7ea98166240b017ca84 Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Wed, 4 Apr 2012 15:02:06 +1000 Subject: pseries: Remove unused fields from VIOsPAPRBus structure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The VIOsPAPRBus structure, used on the pseries machine contains some old fields which are no longer used anywhere. This patch removes them. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Andreas Färber <afaerber@suse.de> --- hw/spapr_vio.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h index d8527be..ae3283c 100644 --- a/hw/spapr_vio.h +++ b/hw/spapr_vio.h @@ -89,8 +89,6 @@ struct VIOsPAPRDevice { struct VIOsPAPRBus { BusState bus; - const char *dt_name, *dt_type, *dt_compatible; - target_ulong signal_mask; int (*init)(VIOsPAPRDevice *dev); int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off); }; -- cgit v1.1 From 5f2e2ba2625d6fa4ecbc2af86e076c20ab84c171 Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Wed, 4 Apr 2012 15:02:07 +1000 Subject: pseries: Consolidate hack for RTAS display-character usage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently the pseries machine contains not one but two somewhat ugly hacks to allow printing of early debug messages before the guest has properly read the device tree. First, we special case H_PUT_TERM_CHAR so that a vtermno of 0 (usually invalid) will look for a suitable vty and use that. This supports Linux's early debug code which will use H_PUT_TERM_CHAR with vtermno==0 before reading the device tree. Second, we support the RTAS display-character call. This takes no vtermno so we assume the address of the default first VTY. This patch makes things more consistent by folding the second hack into the first. Now, display-character uses the existing vty_lookup() function to do the same search for a suitable VTY. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Andreas Färber <afaerber@suse.de> --- hw/spapr_rtas.c | 3 +-- hw/spapr_vio.h | 1 + hw/spapr_vty.c | 4 +--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/hw/spapr_rtas.c b/hw/spapr_rtas.c index 480a4ae..ae18595 100644 --- a/hw/spapr_rtas.c +++ b/hw/spapr_rtas.c @@ -44,8 +44,7 @@ static void rtas_display_character(sPAPREnvironment *spapr, uint32_t nret, target_ulong rets) { uint8_t c = rtas_ld(args, 0); - VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, - SPAPR_VTY_BASE_ADDRESS); + VIOsPAPRDevice *sdev = vty_lookup(spapr, 0); if (!sdev) { rtas_st(rets, 0, -1); diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h index ae3283c..fd29c5e 100644 --- a/hw/spapr_vio.h +++ b/hw/spapr_vio.h @@ -117,6 +117,7 @@ uint64_t ldq_tce(VIOsPAPRDevice *dev, uint64_t taddr); int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq); +VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg); void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len); void spapr_vty_create(VIOsPAPRBus *bus, uint32_t reg, CharDriverState *chardev); void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd); diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c index 60e22b1..a30c040 100644 --- a/hw/spapr_vty.c +++ b/hw/spapr_vty.c @@ -70,8 +70,6 @@ static int spapr_vty_init(VIOsPAPRDevice *sdev) } /* Forward declaration */ -static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg); - static target_ulong h_put_term_char(CPUPPCState *env, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { @@ -195,7 +193,7 @@ VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus) return selected; } -static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg) +VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg) { VIOsPAPRDevice *sdev; -- cgit v1.1 From e2fbb432fc4ec64d0a53c41588ede31450b6c6a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= <afaerber@suse.de> Date: Fri, 6 Apr 2012 14:42:59 +0200 Subject: target-ppc: Drop cpu_ppc_close() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is unused, so avoid QOM'ifying it unneededly. Signed-off-by: Andreas Färber <afaerber@suse.de> Acked-by: David Gibson <david@gibson.dropbear.id.au> --- target-ppc/cpu.h | 1 - target-ppc/helper.c | 6 ------ 2 files changed, 7 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index e7fb364..1d5c602 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1100,7 +1100,6 @@ struct mmu_ctx_t { CPUPPCState *cpu_ppc_init (const char *cpu_model); void ppc_translate_init(void); int cpu_ppc_exec (CPUPPCState *s); -void cpu_ppc_close (CPUPPCState *s); /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero is returned if the signal was handled by the virtual CPU. */ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index f0ea1c3..f61b8b2 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -3214,9 +3214,3 @@ CPUPPCState *cpu_ppc_init (const char *cpu_model) return env; } - -void cpu_ppc_close (CPUPPCState *env) -{ - /* Should also remove all opcode tables... */ - g_free(env); -} -- cgit v1.1 From 12b1143b2807a5b760e477fac0e1028a9760b6c6 Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Wed, 4 Apr 2012 15:02:05 +1000 Subject: target-ppc: Add hooks for handling tcg and kvm limitations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On target-ppc, our table of CPU types and features encodes the features as found on the hardware, regardless of whether these features are actually usable under TCG or KVM. We already have cases where the information from the cpu table must be fixed up to account for limitations in the emulation method we're using. e.g. TCG does not support the DFP and VSX instructions and KVM needs different numbering of the CPUs in order to tell it the correct thread to core mappings. This patch cleans up these hacks to handle emulation limitations by consolidating them into a pair of functions specifically for the purpose. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> [AF: Style and typo fixes, rename new functions and drop ppc_def_t arg] Signed-off-by: Andreas Färber <afaerber@suse.de> --- target-ppc/helper.c | 9 -------- target-ppc/kvm.c | 14 +++++++++++++ target-ppc/kvm_ppc.h | 5 +++++ target-ppc/translate_init.c | 51 +++++++++++++++++++++++++++++++-------------- 4 files changed, 54 insertions(+), 25 deletions(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index f61b8b2..b34dcbe 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -3198,15 +3198,6 @@ CPUPPCState *cpu_ppc_init (const char *cpu_model) if (tcg_enabled()) { ppc_translate_init(); } - /* Adjust cpu index for SMT */ -#if !defined(CONFIG_USER_ONLY) - if (kvm_enabled()) { - int smt = kvmppc_smt_threads(); - - env->cpu_index = (env->cpu_index / smp_threads)*smt - + (env->cpu_index % smp_threads); - } -#endif /* !CONFIG_USER_ONLY */ env->cpu_model_str = cpu_model; cpu_ppc_register_internal(env, def); diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index d929213..c09cc39 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -27,6 +27,7 @@ #include "kvm.h" #include "kvm_ppc.h" #include "cpu.h" +#include "cpus.h" #include "device_tree.h" #include "hw/sysbus.h" #include "hw/spapr.h" @@ -938,6 +939,19 @@ const ppc_def_t *kvmppc_host_cpu_def(void) return spec; } +int kvmppc_fixup_cpu(CPUPPCState *env) +{ + int smt; + + /* Adjust cpu index for SMT */ + smt = kvmppc_smt_threads(); + env->cpu_index = (env->cpu_index / smp_threads) * smt + + (env->cpu_index % smp_threads); + + return 0; +} + + bool kvm_arch_stop_on_emulation_error(CPUPPCState *env) { return true; diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index 8f1267c..34ecad3 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -29,6 +29,7 @@ void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd); int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size); #endif /* !CONFIG_USER_ONLY */ const ppc_def_t *kvmppc_host_cpu_def(void); +int kvmppc_fixup_cpu(CPUPPCState *env); #else @@ -95,6 +96,10 @@ static inline const ppc_def_t *kvmppc_host_cpu_def(void) return NULL; } +static inline int kvmppc_fixup_cpu(CPUPPCState *env) +{ + return -1; +} #endif #ifndef CONFIG_KVM diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index b1f8785..067e07e 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -9889,6 +9889,28 @@ static int gdb_set_spe_reg(CPUPPCState *env, uint8_t *mem_buf, int n) return 0; } +static int ppc_fixup_cpu(CPUPPCState *env) +{ + /* TCG doesn't (yet) emulate some groups of instructions that + * are implemented on some otherwise supported CPUs (e.g. VSX + * and decimal floating point instructions on POWER7). We + * remove unsupported instruction groups from the cpu state's + * instruction masks and hope the guest can cope. For at + * least the pseries machine, the unavailability of these + * instructions can be advertised to the guest via the device + * tree. */ + if ((env->insns_flags & ~PPC_TCG_INSNS) + || (env->insns_flags2 & ~PPC_TCG_INSNS2)) { + fprintf(stderr, "Warning: Disabling some instructions which are not " + "emulated by TCG (0x%" PRIx64 ", 0x%" PRIx64 ")\n", + env->insns_flags & ~PPC_TCG_INSNS, + env->insns_flags2 & ~PPC_TCG_INSNS2); + } + env->insns_flags &= PPC_TCG_INSNS; + env->insns_flags2 &= PPC_TCG_INSNS2; + return 0; +} + int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def) { env->msr_mask = def->msr_mask; @@ -9897,25 +9919,22 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def) env->bus_model = def->bus_model; env->insns_flags = def->insns_flags; env->insns_flags2 = def->insns_flags2; - if (!kvm_enabled()) { - /* TCG doesn't (yet) emulate some groups of instructions that - * are implemented on some otherwise supported CPUs (e.g. VSX - * and decimal floating point instructions on POWER7). We - * remove unsupported instruction groups from the cpu state's - * instruction masks and hope the guest can cope. For at - * least the pseries machine, the unavailability of these - * instructions can be advertise to the guest via the device - * tree. - * - * FIXME: we should have a similar masking for CPU features - * not accessible under KVM, but so far, there aren't any of - * those. */ - env->insns_flags &= PPC_TCG_INSNS; - env->insns_flags2 &= PPC_TCG_INSNS2; - } env->flags = def->flags; env->bfd_mach = def->bfd_mach; env->check_pow = def->check_pow; + + if (kvm_enabled()) { + if (kvmppc_fixup_cpu(env) != 0) { + fprintf(stderr, "Unable to virtualize selected CPU with KVM\n"); + exit(1); + } + } else { + if (ppc_fixup_cpu(env) != 0) { + fprintf(stderr, "Unable to emulate selected CPU with TCG\n"); + exit(1); + } + } + if (create_ppc_opcodes(env, def) < 0) return -1; init_ppc_proc(env, def); -- cgit v1.1 From 1d0cb67da9eff798420d0f6479fec6026c4dc41f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= <afaerber@suse.de> Date: Fri, 6 Apr 2012 14:39:03 +0200 Subject: target-ppc: QOM'ify CPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Embed CPUPPCState as first member of PowerPCCPU. Distinguish between "powerpc-cpu", "powerpc64-cpu" and "embedded-powerpc-cpu". Let CPUClass::reset() call cpu_state_reset() for now. Signed-off-by: Andreas Färber <afaerber@suse.de> Acked-by: David Gibson <david@gibson.dropbear.id.au> --- target-ppc/cpu-qom.h | 77 +++++++++++++++++++++++++++++++++++++++++++++ target-ppc/cpu.h | 2 ++ target-ppc/helper.c | 4 ++- target-ppc/translate_init.c | 37 ++++++++++++++++++++++ 4 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 target-ppc/cpu-qom.h diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h new file mode 100644 index 0000000..fef6f95 --- /dev/null +++ b/target-ppc/cpu-qom.h @@ -0,0 +1,77 @@ +/* + * QEMU PowerPC CPU + * + * Copyright (c) 2012 SUSE LINUX Products GmbH + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * <http://www.gnu.org/licenses/lgpl-2.1.html> + */ +#ifndef QEMU_PPC_CPU_QOM_H +#define QEMU_PPC_CPU_QOM_H + +#include "qemu/cpu.h" +#include "cpu.h" + +#ifdef TARGET_PPC64 +#define TYPE_POWERPC_CPU "powerpc64-cpu" +#elif defined(TARGET_PPCEMB) +#define TYPE_POWERPC_CPU "embedded-powerpc-cpu" +#else +#define TYPE_POWERPC_CPU "powerpc-cpu" +#endif + +#define POWERPC_CPU_CLASS(klass) \ + OBJECT_CLASS_CHECK(PowerPCCPUClass, (klass), TYPE_POWERPC_CPU) +#define POWERPC_CPU(obj) \ + OBJECT_CHECK(PowerPCCPU, (obj), TYPE_POWERPC_CPU) +#define POWERPC_CPU_GET_CLASS(obj) \ + OBJECT_GET_CLASS(PowerPCCPUClass, (obj), TYPE_POWERPC_CPU) + +/** + * PowerPCCPUClass: + * @parent_reset: The parent class' reset handler. + * + * A PowerPC CPU model. + */ +typedef struct PowerPCCPUClass { + /*< private >*/ + CPUClass parent_class; + /*< public >*/ + + void (*parent_reset)(CPUState *cpu); +} PowerPCCPUClass; + +/** + * PowerPCCPU: + * @env: #CPUPPCState + * + * A PowerPC CPU. + */ +typedef struct PowerPCCPU { + /*< private >*/ + CPUState parent_obj; + /*< public >*/ + + CPUPPCState env; +} PowerPCCPU; + +static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env) +{ + return POWERPC_CPU(container_of(env, PowerPCCPU, env)); +} + +#define ENV_GET_CPU(e) CPU(ppc_env_get_cpu(e)) + + +#endif diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 1d5c602..84c9674 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1096,6 +1096,8 @@ struct mmu_ctx_t { }; #endif +#include "cpu-qom.h" + /*****************************************************************************/ CPUPPCState *cpu_ppc_init (const char *cpu_model); void ppc_translate_init(void); diff --git a/target-ppc/helper.c b/target-ppc/helper.c index b34dcbe..0d904dd 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -3186,6 +3186,7 @@ void cpu_state_reset(CPUPPCState *env) CPUPPCState *cpu_ppc_init (const char *cpu_model) { + PowerPCCPU *cpu; CPUPPCState *env; const ppc_def_t *def; @@ -3193,7 +3194,8 @@ CPUPPCState *cpu_ppc_init (const char *cpu_model) if (!def) return NULL; - env = g_malloc0(sizeof(CPUPPCState)); + cpu = POWERPC_CPU(object_new(TYPE_POWERPC_CPU)); + env = &cpu->env; cpu_exec_init(env); if (tcg_enabled()) { ppc_translate_init(); diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 067e07e..e4d15a5 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -10204,3 +10204,40 @@ void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf) ppc_defs[i].name, ppc_defs[i].pvr); } } + +/* CPUClass::reset() */ +static void ppc_cpu_reset(CPUState *s) +{ + PowerPCCPU *cpu = POWERPC_CPU(s); + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); + CPUPPCState *env = &cpu->env; + + pcc->parent_reset(s); + + cpu_state_reset(env); +} + +static void ppc_cpu_class_init(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + CPUClass *cc = CPU_CLASS(oc); + + pcc->parent_reset = cc->reset; + cc->reset = ppc_cpu_reset; +} + +static const TypeInfo ppc_cpu_type_info = { + .name = TYPE_POWERPC_CPU, + .parent = TYPE_CPU, + .instance_size = sizeof(PowerPCCPU), + .abstract = false, + .class_size = sizeof(PowerPCCPUClass), + .class_init = ppc_cpu_class_init, +}; + +static void ppc_cpu_register_types(void) +{ + type_register_static(&ppc_cpu_type_info); +} + +type_init(ppc_cpu_register_types) -- cgit v1.1 From 6cca7ad686de0270fe30ae303e31c6a27b53d7a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= <afaerber@suse.de> Date: Fri, 6 Apr 2012 15:09:01 +0200 Subject: target-ppc: Start QOM'ifying CPU init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move code not dependent on ppc_def_t from cpu_ppc_init() into an initfn. Signed-off-by: Andreas Färber <afaerber@suse.de> Acked-by: David Gibson <david@gibson.dropbear.id.au> --- target-ppc/helper.c | 3 ++- target-ppc/translate_init.c | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 0d904dd..c5de0ea 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -3196,10 +3196,11 @@ CPUPPCState *cpu_ppc_init (const char *cpu_model) cpu = POWERPC_CPU(object_new(TYPE_POWERPC_CPU)); env = &cpu->env; - cpu_exec_init(env); + if (tcg_enabled()) { ppc_translate_init(); } + env->cpu_model_str = cpu_model; cpu_ppc_register_internal(env, def); diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index e4d15a5..5a7ac77 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -10217,6 +10217,14 @@ static void ppc_cpu_reset(CPUState *s) cpu_state_reset(env); } +static void ppc_cpu_initfn(Object *obj) +{ + PowerPCCPU *cpu = POWERPC_CPU(obj); + CPUPPCState *env = &cpu->env; + + cpu_exec_init(env); +} + static void ppc_cpu_class_init(ObjectClass *oc, void *data) { PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -10230,6 +10238,7 @@ static const TypeInfo ppc_cpu_type_info = { .name = TYPE_POWERPC_CPU, .parent = TYPE_CPU, .instance_size = sizeof(PowerPCCPU), + .instance_init = ppc_cpu_initfn, .abstract = false, .class_size = sizeof(PowerPCCPUClass), .class_init = ppc_cpu_class_init, -- cgit v1.1 From a13895420561da4f8eae03f4d423a7c2fdb83f65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= <afaerber@suse.de> Date: Fri, 6 Apr 2012 15:35:34 +0200 Subject: target-ppc: QOM'ify CPU reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move code from cpu_state_reset() into ppc_cpu_reset(). Reorder #include of helper_regs.h to use it in translate_init.c. Adjust whitespace and add braces. Signed-off-by: Andreas Färber <afaerber@suse.de> Acked-by: David Gibson <david@gibson.dropbear.id.au> --- target-ppc/helper.c | 45 +------------------------------------------- target-ppc/translate.c | 2 +- target-ppc/translate_init.c | 46 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 47 insertions(+), 46 deletions(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index c5de0ea..c610ce3 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -3138,50 +3138,7 @@ void cpu_dump_rfi (target_ulong RA, target_ulong msr) void cpu_state_reset(CPUPPCState *env) { - target_ulong msr; - - if (qemu_loglevel_mask(CPU_LOG_RESET)) { - qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); - log_cpu_state(env, 0); - } - - msr = (target_ulong)0; - if (0) { - /* XXX: find a suitable condition to enable the hypervisor mode */ - msr |= (target_ulong)MSR_HVB; - } - msr |= (target_ulong)0 << MSR_AP; /* TO BE CHECKED */ - msr |= (target_ulong)0 << MSR_SA; /* TO BE CHECKED */ - msr |= (target_ulong)1 << MSR_EP; -#if defined (DO_SINGLE_STEP) && 0 - /* Single step trace mode */ - msr |= (target_ulong)1 << MSR_SE; - msr |= (target_ulong)1 << MSR_BE; -#endif -#if defined(CONFIG_USER_ONLY) - msr |= (target_ulong)1 << MSR_FP; /* Allow floating point usage */ - msr |= (target_ulong)1 << MSR_VR; /* Allow altivec usage */ - msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */ - msr |= (target_ulong)1 << MSR_PR; -#else - env->excp_prefix = env->hreset_excp_prefix; - env->nip = env->hreset_vector | env->excp_prefix; - if (env->mmu_model != POWERPC_MMU_REAL) - ppc_tlb_invalidate_all(env); -#endif - env->msr = msr & env->msr_mask; -#if defined(TARGET_PPC64) - if (env->mmu_model & POWERPC_MMU_64) - env->msr |= (1ULL << MSR_SF); -#endif - hreg_compute_hflags(env); - env->reserve_addr = (target_ulong)-1ULL; - /* Be sure no exception or interrupt is pending */ - env->pending_interrupts = 0; - env->exception_index = POWERPC_EXCP_NONE; - env->error_code = 0; - /* Flush all TLBs */ - tlb_flush(env, 1); + cpu_reset(ENV_GET_CPU(env)); } CPUPPCState *cpu_ppc_init (const char *cpu_model) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index c9a503a..cf59765 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -9306,8 +9306,8 @@ GEN_SPEOP_LDST(evstwwe, 0x1C, 2), GEN_SPEOP_LDST(evstwwo, 0x1E, 2), }; -#include "translate_init.c" #include "helper_regs.h" +#include "translate_init.c" /*****************************************************************************/ /* Misc PowerPC helpers */ diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 5a7ac77..025122d 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -10211,10 +10211,54 @@ static void ppc_cpu_reset(CPUState *s) PowerPCCPU *cpu = POWERPC_CPU(s); PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); CPUPPCState *env = &cpu->env; + target_ulong msr; + + if (qemu_loglevel_mask(CPU_LOG_RESET)) { + qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); + log_cpu_state(env, 0); + } pcc->parent_reset(s); - cpu_state_reset(env); + msr = (target_ulong)0; + if (0) { + /* XXX: find a suitable condition to enable the hypervisor mode */ + msr |= (target_ulong)MSR_HVB; + } + msr |= (target_ulong)0 << MSR_AP; /* TO BE CHECKED */ + msr |= (target_ulong)0 << MSR_SA; /* TO BE CHECKED */ + msr |= (target_ulong)1 << MSR_EP; +#if defined(DO_SINGLE_STEP) && 0 + /* Single step trace mode */ + msr |= (target_ulong)1 << MSR_SE; + msr |= (target_ulong)1 << MSR_BE; +#endif +#if defined(CONFIG_USER_ONLY) + msr |= (target_ulong)1 << MSR_FP; /* Allow floating point usage */ + msr |= (target_ulong)1 << MSR_VR; /* Allow altivec usage */ + msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */ + msr |= (target_ulong)1 << MSR_PR; +#else + env->excp_prefix = env->hreset_excp_prefix; + env->nip = env->hreset_vector | env->excp_prefix; + if (env->mmu_model != POWERPC_MMU_REAL) { + ppc_tlb_invalidate_all(env); + } +#endif + env->msr = msr & env->msr_mask; +#if defined(TARGET_PPC64) + if (env->mmu_model & POWERPC_MMU_64) { + env->msr |= (1ULL << MSR_SF); + } +#endif + hreg_compute_hflags(env); + env->reserve_addr = (target_ulong)-1ULL; + /* Be sure no exception or interrupt is pending */ + env->pending_interrupts = 0; + env->exception_index = POWERPC_EXCP_NONE; + env->error_code = 0; + /* Flush all TLBs */ + tlb_flush(env, 1); } static void ppc_cpu_initfn(Object *obj) -- cgit v1.1 From 5724753e6576fc26ff4a563a6c2ccb8ce3b02cb8 Mon Sep 17 00:00:00 2001 From: Stefan Weil <sw@weilnetz.de> Date: Sun, 15 Apr 2012 16:13:48 +0200 Subject: target-ppc: Fix type casts for w64 (uintptr_t) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This changes nothing for other hosts. Signed-off-by: Stefan Weil <sw@weilnetz.de> Signed-off-by: Andreas Färber <afaerber@suse.de> --- target-ppc/translate_init.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 025122d..fdc0a5f 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -9504,12 +9504,12 @@ enum { static inline int is_indirect_opcode (void *handler) { - return ((unsigned long)handler & 0x03) == PPC_INDIRECT; + return ((uintptr_t)handler & 0x03) == PPC_INDIRECT; } static inline opc_handler_t **ind_table(void *handler) { - return (opc_handler_t **)((unsigned long)handler & ~3); + return (opc_handler_t **)((uintptr_t)handler & ~3); } /* Instruction table creation */ @@ -9528,7 +9528,7 @@ static int create_new_table (opc_handler_t **table, unsigned char idx) tmp = malloc(0x20 * sizeof(opc_handler_t)); fill_new_table(tmp, 0x20); - table[idx] = (opc_handler_t *)((unsigned long)tmp | PPC_INDIRECT); + table[idx] = (opc_handler_t *)((uintptr_t)tmp | PPC_INDIRECT); return 0; } -- cgit v1.1 From a5cabbda760c798bb551d53a697058de28fce51c Mon Sep 17 00:00:00 2001 From: Meador Inge <meadori@codesourcery.com> Date: Tue, 10 Apr 2012 15:04:23 -0500 Subject: target-ppc: Init dcache and icache size for e500 user mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit f7aa558396dd0f6b7a2b22c05cb503c655854102 pulled the dcache and icache line size initialization inside of a '#if !defined(CONFIG_USER_ONLY)' block. This is not correct because instructions like 'dcbz' need the dcache size initialized even for user mode. Signed-off-by: Meador Inge <meadori@codesourcery.com> Cc: Varun Sethi <Varun.Sethi@freescale.com> [AF: Simplify #ifdefs by using cache line size 32 for *-user as before] Suggested-by: Scott Wood <scottwood@freescale.com> Signed-off-by: Andreas Färber <afaerber@suse.de> --- target-ppc/translate_init.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index fdc0a5f..ba4b84d 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -4462,7 +4462,10 @@ static void init_proc_e500 (CPUPPCState *env, int version) &spr_read_spefscr, &spr_write_spefscr, 0x00000000); /* Memory management */ -#if !defined(CONFIG_USER_ONLY) +#if defined(CONFIG_USER_ONLY) + env->dcache_line_size = 32; + env->icache_line_size = 32; +#else /* !defined(CONFIG_USER_ONLY) */ env->nb_pids = 3; env->nb_ways = 2; env->id_tlbs = 0; -- cgit v1.1 From 45e45ed2d61fb287adf03e49c74c152bfd2c975a Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Mon, 19 Mar 2012 23:57:36 +0100 Subject: target-ppc/machine.c: Drop unnecessary ifdefs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit machine.c is only compiled for softmmu targets, so checks for !defined(CONFIG_USER_ONLY) are unnecessary and can be dropped. Signed-off-by: Juan Quintela <quintela@redhat.com> [AF: Use more verbose commit message suggested by PMM] Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Andreas Färber <afaerber@suse.de> --- target-ppc/machine.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/target-ppc/machine.c b/target-ppc/machine.c index 70e2582..d6c2ee4 100644 --- a/target-ppc/machine.c +++ b/target-ppc/machine.c @@ -32,7 +32,6 @@ void cpu_save(QEMUFile *f, void *opaque) } qemu_put_be32s(f, &env->fpscr); qemu_put_sbe32s(f, &env->access_type); -#if !defined(CONFIG_USER_ONLY) #if defined(TARGET_PPC64) qemu_put_betls(f, &env->asr); qemu_put_sbe32s(f, &env->slb_nr); @@ -62,7 +61,6 @@ void cpu_save(QEMUFile *f, void *opaque) } for (i = 0; i < 4; i++) qemu_put_betls(f, &env->pb[i]); -#endif for (i = 0; i < 1024; i++) qemu_put_betls(f, &env->spr[i]); qemu_put_be32s(f, &env->vscr); @@ -72,7 +70,6 @@ void cpu_save(QEMUFile *f, void *opaque) qemu_put_be32s(f, &env->flags); qemu_put_sbe32s(f, &env->error_code); qemu_put_be32s(f, &env->pending_interrupts); -#if !defined(CONFIG_USER_ONLY) qemu_put_be32s(f, &env->irq_input_state); for (i = 0; i < POWERPC_EXCP_NB; i++) qemu_put_betls(f, &env->excp_vectors[i]); @@ -81,7 +78,6 @@ void cpu_save(QEMUFile *f, void *opaque) qemu_put_betls(f, &env->ivor_mask); qemu_put_betls(f, &env->ivpr_mask); qemu_put_betls(f, &env->hreset_vector); -#endif qemu_put_betls(f, &env->nip); qemu_put_betls(f, &env->hflags); qemu_put_betls(f, &env->hflags_nmsr); @@ -120,7 +116,6 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) } qemu_get_be32s(f, &env->fpscr); qemu_get_sbe32s(f, &env->access_type); -#if !defined(CONFIG_USER_ONLY) #if defined(TARGET_PPC64) qemu_get_betls(f, &env->asr); qemu_get_sbe32s(f, &env->slb_nr); @@ -150,7 +145,6 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) } for (i = 0; i < 4; i++) qemu_get_betls(f, &env->pb[i]); -#endif for (i = 0; i < 1024; i++) qemu_get_betls(f, &env->spr[i]); ppc_store_sdr1(env, sdr1); @@ -161,7 +155,6 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) qemu_get_be32s(f, &env->flags); qemu_get_sbe32s(f, &env->error_code); qemu_get_be32s(f, &env->pending_interrupts); -#if !defined(CONFIG_USER_ONLY) qemu_get_be32s(f, &env->irq_input_state); for (i = 0; i < POWERPC_EXCP_NB; i++) qemu_get_betls(f, &env->excp_vectors[i]); @@ -170,7 +163,6 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) qemu_get_betls(f, &env->ivor_mask); qemu_get_betls(f, &env->ivpr_mask); qemu_get_betls(f, &env->hreset_vector); -#endif qemu_get_betls(f, &env->nip); qemu_get_betls(f, &env->hflags); qemu_get_betls(f, &env->hflags_nmsr); -- cgit v1.1 From 92615a5ab96cd2b4981e2aaef40bece6cd7553b6 Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Mon, 2 Apr 2012 14:17:35 +1000 Subject: pseries: Fix RTAS based config access MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On the pseries platform, access to PCI config space is via RTAS calls( which go to the hypervisor) rather than MMIO. This means we don't use the same code path as nearly everyone else which goes through pci_host.c and we're missing some of the parameter checking along the way. We do have some parameter checking in the RTAS calls, but it's not enough. It checks for overruns, but does not check for unaligned accesses, oversized accesses (which means the guest could trigger an assertion failure from pci_host_config_{read,write}_common(). Worse it doesn't do the basic checking for the number of RTAS arguments and results before accessing them. This patch fixes these bugs. Cc: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: David Gibson <david@gibson.dropbear.id.au> [AF: Fix typos spotted by mst] Signed-off-by: Andreas Färber <afaerber@suse.de> --- hw/spapr_pci.c | 117 ++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 79 insertions(+), 38 deletions(-) diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c index e7ef551..a564c00 100644 --- a/hw/spapr_pci.c +++ b/hw/spapr_pci.c @@ -57,26 +57,38 @@ static PCIDevice *find_dev(sPAPREnvironment *spapr, static uint32_t rtas_pci_cfgaddr(uint32_t arg) { + /* This handles the encoding of extended config space addresses */ return ((arg >> 20) & 0xf00) | (arg & 0xff); } -static uint32_t rtas_read_pci_config_do(PCIDevice *pci_dev, uint32_t addr, - uint32_t limit, uint32_t len) +static void finish_read_pci_config(sPAPREnvironment *spapr, uint64_t buid, + uint32_t addr, uint32_t size, + target_ulong rets) { - if ((addr + len) <= limit) { - return pci_host_config_read_common(pci_dev, addr, limit, len); - } else { - return ~0x0; + PCIDevice *pci_dev; + uint32_t val; + + if ((size != 1) && (size != 2) && (size != 4)) { + /* access must be 1, 2 or 4 bytes */ + rtas_st(rets, 0, -1); + return; } -} -static void rtas_write_pci_config_do(PCIDevice *pci_dev, uint32_t addr, - uint32_t limit, uint32_t val, - uint32_t len) -{ - if ((addr + len) <= limit) { - pci_host_config_write_common(pci_dev, addr, limit, val, len); + pci_dev = find_dev(spapr, buid, addr); + addr = rtas_pci_cfgaddr(addr); + + if (!pci_dev || (addr % size) || (addr >= pci_config_size(pci_dev))) { + /* Access must be to a valid device, within bounds and + * naturally aligned */ + rtas_st(rets, 0, -1); + return; } + + val = pci_host_config_read_common(pci_dev, addr, + pci_config_size(pci_dev), size); + + rtas_st(rets, 0, 0); + rtas_st(rets, 1, val); } static void rtas_ibm_read_pci_config(sPAPREnvironment *spapr, @@ -84,19 +96,19 @@ static void rtas_ibm_read_pci_config(sPAPREnvironment *spapr, target_ulong args, uint32_t nret, target_ulong rets) { - uint32_t val, size, addr; - uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2); - PCIDevice *dev = find_dev(spapr, buid, rtas_ld(args, 0)); + uint64_t buid; + uint32_t size, addr; - if (!dev) { + if ((nargs != 4) || (nret != 2)) { rtas_st(rets, 0, -1); return; } + + buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2); size = rtas_ld(args, 3); - addr = rtas_pci_cfgaddr(rtas_ld(args, 0)); - val = rtas_read_pci_config_do(dev, addr, pci_config_size(dev), size); - rtas_st(rets, 0, 0); - rtas_st(rets, 1, val); + addr = rtas_ld(args, 0); + + finish_read_pci_config(spapr, buid, addr, size, rets); } static void rtas_read_pci_config(sPAPREnvironment *spapr, @@ -104,18 +116,45 @@ static void rtas_read_pci_config(sPAPREnvironment *spapr, target_ulong args, uint32_t nret, target_ulong rets) { - uint32_t val, size, addr; - PCIDevice *dev = find_dev(spapr, 0, rtas_ld(args, 0)); + uint32_t size, addr; - if (!dev) { + if ((nargs != 2) || (nret != 2)) { rtas_st(rets, 0, -1); return; } + size = rtas_ld(args, 1); - addr = rtas_pci_cfgaddr(rtas_ld(args, 0)); - val = rtas_read_pci_config_do(dev, addr, pci_config_size(dev), size); + addr = rtas_ld(args, 0); + + finish_read_pci_config(spapr, 0, addr, size, rets); +} + +static void finish_write_pci_config(sPAPREnvironment *spapr, uint64_t buid, + uint32_t addr, uint32_t size, + uint32_t val, target_ulong rets) +{ + PCIDevice *pci_dev; + + if ((size != 1) && (size != 2) && (size != 4)) { + /* access must be 1, 2 or 4 bytes */ + rtas_st(rets, 0, -1); + return; + } + + pci_dev = find_dev(spapr, buid, addr); + addr = rtas_pci_cfgaddr(addr); + + if (!pci_dev || (addr % size) || (addr >= pci_config_size(pci_dev))) { + /* Access must be to a valid device, within bounds and + * naturally aligned */ + rtas_st(rets, 0, -1); + return; + } + + pci_host_config_write_common(pci_dev, addr, pci_config_size(pci_dev), + val, size); + rtas_st(rets, 0, 0); - rtas_st(rets, 1, val); } static void rtas_ibm_write_pci_config(sPAPREnvironment *spapr, @@ -123,19 +162,20 @@ static void rtas_ibm_write_pci_config(sPAPREnvironment *spapr, target_ulong args, uint32_t nret, target_ulong rets) { + uint64_t buid; uint32_t val, size, addr; - uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2); - PCIDevice *dev = find_dev(spapr, buid, rtas_ld(args, 0)); - if (!dev) { + if ((nargs != 5) || (nret != 1)) { rtas_st(rets, 0, -1); return; } + + buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2); val = rtas_ld(args, 4); size = rtas_ld(args, 3); - addr = rtas_pci_cfgaddr(rtas_ld(args, 0)); - rtas_write_pci_config_do(dev, addr, pci_config_size(dev), val, size); - rtas_st(rets, 0, 0); + addr = rtas_ld(args, 0); + + finish_write_pci_config(spapr, buid, addr, size, val, rets); } static void rtas_write_pci_config(sPAPREnvironment *spapr, @@ -144,17 +184,18 @@ static void rtas_write_pci_config(sPAPREnvironment *spapr, uint32_t nret, target_ulong rets) { uint32_t val, size, addr; - PCIDevice *dev = find_dev(spapr, 0, rtas_ld(args, 0)); - if (!dev) { + if ((nargs != 3) || (nret != 1)) { rtas_st(rets, 0, -1); return; } + + val = rtas_ld(args, 2); size = rtas_ld(args, 1); - addr = rtas_pci_cfgaddr(rtas_ld(args, 0)); - rtas_write_pci_config_do(dev, addr, pci_config_size(dev), val, size); - rtas_st(rets, 0, 0); + addr = rtas_ld(args, 0); + + finish_write_pci_config(spapr, 0, addr, size, val, rets); } static int pci_spapr_map_irq(PCIDevice *pci_dev, int irq_num) -- cgit v1.1 From e2d9154dfab73c36ead3cd368e7bc702dfb2ab68 Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Thu, 12 Apr 2012 12:44:11 +1000 Subject: pseries: Remove old debug leftovers from spapr_vscsi MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PAPR VSCSI emulation contains a few lines of code which were once used for debug but now do nothing at all. This patch removes them. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Andreas Färber <afaerber@suse.de> --- hw/spapr_vscsi.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c index 2167017..3530a38 100644 --- a/hw/spapr_vscsi.c +++ b/hw/spapr_vscsi.c @@ -99,10 +99,6 @@ typedef struct { vscsi_req reqs[VSCSI_REQ_LIMIT]; } VSCSIState; -/* XXX Debug only */ -static VSCSIState *dbg_vscsi_state; - - static struct vscsi_req *vscsi_get_req(VSCSIState *s) { vscsi_req *req; @@ -902,8 +898,6 @@ static int spapr_vscsi_init(VIOsPAPRDevice *dev) VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev); int i; - dbg_vscsi_state = s; - /* Initialize qemu request tags */ memset(s->reqs, 0, sizeof(s->reqs)); for (i = 0; i < VSCSI_REQ_LIMIT; i++) { -- cgit v1.1 From 91067bf8689ad4a4489a5080812619a9eb932716 Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Thu, 12 Apr 2012 12:44:12 +1000 Subject: pseries: Remove old hcalls hook stub MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some time ago we removed all use of the 'hcalls' callback in the pseries VIO code, which was used to workaround an ordering problem which has since been solved properly. However, the function pointer for the hook remains. This patch cleans it away. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Andreas Färber <afaerber@suse.de> --- hw/spapr_vio.h | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h index fd29c5e..626d04f 100644 --- a/hw/spapr_vio.h +++ b/hw/spapr_vio.h @@ -64,7 +64,6 @@ typedef struct VIOsPAPRDeviceClass { const char *dt_name, *dt_type, *dt_compatible; target_ulong signal_mask; int (*init)(VIOsPAPRDevice *dev); - void (*hcalls)(VIOsPAPRBus *bus); int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off); } VIOsPAPRDeviceClass; -- cgit v1.1 From b1c7f725a3bc5fec87912e907066edd6b80b878c Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Thu, 12 Apr 2012 12:44:13 +1000 Subject: pseries: Correctly use the device model reset hooks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Recently we added code to properly clean away VIO CRQs on reset However, this directly uses qemu_register, rather than the existing device model reset callbacks. This patch cleans this up by adding proper use of the reset hook to the VIO bus model. The existing CRQ reset code is converted to the new method. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Andreas Färber <afaerber@suse.de> --- hw/spapr_vio.c | 12 ++++++++---- hw/spapr_vio.h | 1 + 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index 0bf2c31..fccf48b 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -648,13 +648,18 @@ static int spapr_vio_check_reg(VIOsPAPRDevice *sdev) return 0; } -static void spapr_vio_busdev_reset(void *opaque) +static void spapr_vio_busdev_reset(DeviceState *qdev) { - VIOsPAPRDevice *dev = (VIOsPAPRDevice *)opaque; + VIOsPAPRDevice *dev = DO_UPCAST(VIOsPAPRDevice, qdev, qdev); + VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); if (dev->crq.qsize) { free_crq(dev); } + + if (pc->reset) { + pc->reset(dev); + } } static int spapr_vio_busdev_init(DeviceState *qdev) @@ -685,8 +690,6 @@ static int spapr_vio_busdev_init(DeviceState *qdev) rtce_init(dev); - qemu_register_reset(spapr_vio_busdev_reset, dev); - return pc->init(dev); } @@ -776,6 +779,7 @@ static void vio_spapr_device_class_init(ObjectClass *klass, void *data) { DeviceClass *k = DEVICE_CLASS(klass); k->init = spapr_vio_busdev_init; + k->reset = spapr_vio_busdev_reset; k->bus_info = &spapr_vio_bus_info; } diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h index 626d04f..10ab359 100644 --- a/hw/spapr_vio.h +++ b/hw/spapr_vio.h @@ -64,6 +64,7 @@ typedef struct VIOsPAPRDeviceClass { const char *dt_name, *dt_type, *dt_compatible; target_ulong signal_mask; int (*init)(VIOsPAPRDevice *dev); + void (*reset)(VIOsPAPRDevice *dev); int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off); } VIOsPAPRDeviceClass; -- cgit v1.1 From 3cabba609de07e06b3dacf4f30403f6e9e293f2c Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Thu, 12 Apr 2012 12:44:14 +1000 Subject: pseries: Reset vscsi properly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently the PAPR vscsi implementation does not properly clear its table of request tags when the system is reset. This patch adds a reset hook to do so. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Andreas Färber <afaerber@suse.de> --- hw/spapr_vscsi.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c index 3530a38..538e0b7 100644 --- a/hw/spapr_vscsi.c +++ b/hw/spapr_vscsi.c @@ -893,16 +893,20 @@ static const struct SCSIBusInfo vscsi_scsi_info = { .cancel = vscsi_request_cancelled }; -static int spapr_vscsi_init(VIOsPAPRDevice *dev) +static void spapr_vscsi_reset(VIOsPAPRDevice *dev) { VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev); int i; - /* Initialize qemu request tags */ memset(s->reqs, 0, sizeof(s->reqs)); for (i = 0; i < VSCSI_REQ_LIMIT; i++) { s->reqs[i].qtag = i; } +} + +static int spapr_vscsi_init(VIOsPAPRDevice *dev) +{ + VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev); dev->crq.SendFunc = vscsi_do_crq; @@ -952,6 +956,7 @@ static void spapr_vscsi_class_init(ObjectClass *klass, void *data) VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass); k->init = spapr_vscsi_init; + k->reset = spapr_vscsi_reset; k->devnode = spapr_vscsi_devnode; k->dt_name = "v-scsi"; k->dt_type = "vscsi"; -- cgit v1.1 From c17491b63e198ac48d533f8a9d301d11c5880a36 Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Thu, 12 Apr 2012 12:44:15 +1000 Subject: pseries: Fix reset of VIO network device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, the PAPR VIO network device does not have a reset handler. This means that after a hard reset, H_REGISTER_LOGICAL_LAN will return an error when the new guest boot attempts to initialize the device. This patch corrects this, adding a suitable reset hook. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Andreas Färber <afaerber@suse.de> --- hw/spapr_llan.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c index 32dce17..e18d2eb 100644 --- a/hw/spapr_llan.c +++ b/hw/spapr_llan.c @@ -182,6 +182,15 @@ static NetClientInfo net_spapr_vlan_info = { .receive = spapr_vlan_receive, }; +static void spapr_vlan_reset(VIOsPAPRDevice *sdev) +{ + VIOsPAPRVLANDevice *dev = DO_UPCAST(VIOsPAPRVLANDevice, sdev, sdev); + + dev->buf_list = 0; + dev->rx_bufs = 0; + dev->isopen = 0; +} + static int spapr_vlan_init(VIOsPAPRDevice *sdev) { VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev; @@ -335,9 +344,7 @@ static target_ulong h_free_logical_lan(CPUPPCState *env, sPAPREnvironment *spapr return H_RESOURCE; } - dev->buf_list = 0; - dev->rx_bufs = 0; - dev->isopen = 0; + spapr_vlan_reset(sdev); return H_SUCCESS; } @@ -484,6 +491,7 @@ static void spapr_vlan_class_init(ObjectClass *klass, void *data) VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass); k->init = spapr_vlan_init; + k->reset = spapr_vlan_reset; k->devnode = spapr_vlan_devnode; k->dt_name = "l-lan"; k->dt_type = "network"; -- cgit v1.1