From d43b45e220ae82081e389ae113f6f03d9294fdcf Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 1 Nov 2011 16:49:05 +0000 Subject: [PATCH 1/9] pseries: Fix initialization of sPAPREnvironment structure Since we added PCI support to the pseries machine, we include a qlist of PCI host bridges in the sPAPREnvironment structure. However this list was never properly initialized it. Somehow we got away with this until some other recent change broke it, and we now segfault immediately on startup. This patch adds the required QLIST_INIT(), and while we're at it makes sure we initialize the rest of the sPAPREnvironment structure to 0, to avoid future nasty surprises. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/spapr.c b/hw/spapr.c index bdaa938b6b..40cfc9be1f 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -407,7 +407,9 @@ static void ppc_spapr_init(ram_addr_t ram_size, long pteg_shift = 17; char *filename; - spapr = g_malloc(sizeof(*spapr)); + spapr = g_malloc0(sizeof(*spapr)); + QLIST_INIT(&spapr->phbs); + cpu_ppc_hypercall = emulate_spapr_hypercall; /* Allocate RMA if necessary */ From 9df3b45dd4e6e5a856a08e5c7799a3434e9e5ccf Mon Sep 17 00:00:00 2001 From: David Gibson Date: Sun, 30 Oct 2011 19:57:33 +0000 Subject: [PATCH 2/9] tcg-ppc64: Fix compile errors for userspace only builds with gcc 4.6 tcg/ppc64/tcg-target.c has a couple of places where variables are set unconditionally, but otherwise used only for softmmu builds, not userspace only builds. This causes compiler warnings (which are fatal by default) when compiling for a ppc64 host with gcc 4.6. This patch fixes the problem by moving the code which defines and sets the variables into the CONFIG_SOFTMMU guarded regions. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- tcg/ppc64/tcg-target.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tcg/ppc64/tcg-target.c b/tcg/ppc64/tcg-target.c index 3d24cd4da4..41f1e85cc9 100644 --- a/tcg/ppc64/tcg-target.c +++ b/tcg/ppc64/tcg-target.c @@ -616,18 +616,19 @@ static void tcg_out_tlb_read (TCGContext *s, int r0, int r1, int r2, static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc) { - int addr_reg, data_reg, r0, r1, rbase, mem_index, s_bits, bswap; + int addr_reg, data_reg, r0, r1, rbase, bswap; #ifdef CONFIG_SOFTMMU - int r2; + int r2, mem_index, s_bits; void *label1_ptr, *label2_ptr; #endif data_reg = *args++; addr_reg = *args++; + +#ifdef CONFIG_SOFTMMU mem_index = *args; s_bits = opc & 3; -#ifdef CONFIG_SOFTMMU r0 = 3; r1 = 4; r2 = 0; @@ -763,17 +764,18 @@ static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc) static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc) { - int addr_reg, r0, r1, rbase, data_reg, mem_index, bswap; + int addr_reg, r0, r1, rbase, data_reg, bswap; #ifdef CONFIG_SOFTMMU - int r2; + int r2, mem_index; void *label1_ptr, *label2_ptr; #endif data_reg = *args++; addr_reg = *args++; - mem_index = *args; #ifdef CONFIG_SOFTMMU + mem_index = *args; + r0 = 3; r1 = 4; r2 = 0; From ee2b39946312952f5aa99cf9b7bab238cd5b6329 Mon Sep 17 00:00:00 2001 From: Sebastian Bauer Date: Wed, 10 Aug 2011 01:41:48 +0000 Subject: [PATCH 3/9] PPC: Fix for the gdb single step problem on an rfi instruction When using gdb to single step a ppc interrupt routine, the execution flow passes the rfi instruction without actually returning from the interrupt. The patch fixes this by avoiding to update the nip when the debug exception is raised and a previous POWERPC_EXCP_SYNC was set. The latter is the case only, if code for rfi or a related instruction was generated. Signed-off-by: Sebastian Bauer Signed-off-by: Alexander Graf --- target-ppc/translate.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 99e995c7b6..66eae30209 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -298,8 +298,10 @@ static inline void gen_debug_exception(DisasContext *ctx) { TCGv_i32 t0; - if (ctx->exception != POWERPC_EXCP_BRANCH) + if ((ctx->exception != POWERPC_EXCP_BRANCH) && + (ctx->exception != POWERPC_EXCP_SYNC)) { gen_update_nip(ctx, ctx->nip); + } t0 = tcg_const_i32(EXCP_DEBUG); gen_helper_raise_exception(t0); tcg_temp_free_i32(t0); From 92c93a816a8c04071264f9fb47cbc90a5e1ae5d8 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Sun, 13 Nov 2011 17:18:57 +0000 Subject: [PATCH 4/9] pseries: Correct RAM size check for SLOF The SLOF firmware used on the pseries machine needs a reasonable amount of (guest) RAM in order to run, so we have a check in the machine init function to check that this is available. However, SLOF runs in real mode (MMU off) which means it can only actually access the RMA (Real Mode Area), not all of RAM. In many cases the RMA is the same as all RAM, but when running with Book3S HV KVM on PowerPC 970, the RMA must be especially allocated to be (host) physically contiguous. In this case, the RMA size is determined by what the host admin allocated at boot time, and will usually be less than the whole guest RAM size. This patch corrects the test to see if SLOF has enough memory for this case. In addition, more recent versions of SLOF that were committed earlier don't need quite as much memory as earlier versions. Therefore, this patch also reduces the amount of RAM we require to run SLOF. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/spapr.c b/hw/spapr.c index 40cfc9be1f..2b901f105e 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -57,7 +57,7 @@ #define FW_MAX_SIZE 0x400000 #define FW_FILE_NAME "slof.bin" -#define MIN_RAM_SLOF 512UL +#define MIN_RMA_SLOF 128UL #define TIMEBASE_FREQ 512000000ULL @@ -562,9 +562,9 @@ static void ppc_spapr_init(ram_addr_t ram_size, spapr->entry_point = KERNEL_LOAD_ADDR; } else { - if (ram_size < (MIN_RAM_SLOF << 20)) { + if (rma_size < (MIN_RMA_SLOF << 20)) { fprintf(stderr, "qemu: pSeries SLOF firmware requires >= " - "%ldM guest RAM\n", MIN_RAM_SLOF); + "%ldM guest RMA (Real Mode Area memory)\n", MIN_RMA_SLOF); exit(1); } filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, FW_FILE_NAME); From 5435352ce6abfb8a7540ae7d47e981d329120cca Mon Sep 17 00:00:00 2001 From: David Gibson Date: Sun, 13 Nov 2011 17:18:58 +0000 Subject: [PATCH 5/9] pseries: Fix buggy spapr_vio_find_by_reg() The spapr_vio_find_by_reg() function in hw/spapr_vio.c is supposed to find the device structure for a PAPR virtual IO device with the given reg value, and return NULL if none exists. It does the first ok, but if no device with that reg exists, it just returns the last device traversed in the list. This patch fixes it. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr_vio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index 25cfc9d912..b7b3ddd116 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -66,11 +66,11 @@ VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg) QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) { dev = (VIOsPAPRDevice *)qdev; if (dev->reg == reg) { - break; + return dev; } } - return dev; + return NULL; } #ifdef CONFIG_FDT From 57285302af51a8bae334c03e1f8243e935373953 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sun, 13 Nov 2011 17:18:59 +0000 Subject: [PATCH 6/9] pseries: Check we have a chardev in spapr_vty_init() If qemu is run like: qemu-system-ppc64 -nodefaults -device spapr-vty We end up in spapr_vty_init() with dev->chardev == NULL. Currently that leads to a segfault because we unconditionally call qemu_chr_add_handlers(). Although we could make that call conditional, I think a spapr-vty without a chardev is basically useless so fail the init. This is similar to what the serial code does for example. Signed-off-by: Michael Ellerman Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr_vty.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c index a9d4b035e2..f4f3ee32ae 100644 --- a/hw/spapr_vty.c +++ b/hw/spapr_vty.c @@ -58,6 +58,11 @@ static int spapr_vty_init(VIOsPAPRDevice *sdev) { VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev; + if (!dev->chardev) { + fprintf(stderr, "spapr-vty: Can't create vty without a chardev!\n"); + exit(1); + } + qemu_chr_add_handlers(dev->chardev, vty_can_receive, vty_receive, NULL, dev); From 5afdec404e73a578c37221b9ea226d582814acb5 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sun, 13 Nov 2011 17:19:00 +0000 Subject: [PATCH 7/9] pseries: Default reg for vty should be SPAPR_VTY_BASE_ADDRESS In commit b4a78527359a4540d84d4cdf629d01cbb262f698 ("Place pseries vty devices at addresses more similar to existing machines"), we changed the default reg for the vty to 0x30000000, however we didn't update the default value for a user specified vty device. Fix that. Signed-off-by: Michael Ellerman Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr_vty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c index f4f3ee32ae..815039501f 100644 --- a/hw/spapr_vty.c +++ b/hw/spapr_vty.c @@ -145,7 +145,7 @@ static VIOsPAPRDeviceInfo spapr_vty = { .qdev.name = "spapr-vty", .qdev.size = sizeof(VIOsPAPRVTYDevice), .qdev.props = (Property[]) { - DEFINE_SPAPR_PROPERTIES(VIOsPAPRVTYDevice, sdev, 0, 0), + DEFINE_SPAPR_PROPERTIES(VIOsPAPRVTYDevice, sdev, SPAPR_VTY_BASE_ADDRESS, 0), DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev), DEFINE_PROP_END_OF_LIST(), }, From 3feef8ad17af7307373b9e88b9d7ecb98eeb99da Mon Sep 17 00:00:00 2001 From: David Gibson Date: Sun, 13 Nov 2011 17:19:01 +0000 Subject: [PATCH 8/9] pseries: Allow kernel's early debug output to work The PAPR specification defines a virtual TTY/console interface for guest OSes to use via the H_PUT_TERM_CHAR and H_GET_TERM_CHAR hypercalls. There can be multiple virtual ttys, so these take a "termno" parameter. This encodes which vty to use as the 'reg' property on the device tree node associated with that vty. However, with the early debug options enabled, the Linux kernel will attempt debugging output through the vty very early, before it has read the device tree. In this case it always uses a termno of 0. This works on the existing PowerVM hypervisor, so we assume there must be a hack / feature in there which interprets termno==0 to mean the default primary console. To help with debugging kernels, including existing distribution kernels, this patch implements a similar feature / hack in qemu. If termno==0 is supplied to H_{GET,PUT}_TERM_CHAR, they use the first available vty device instead. We need to be careful in the case that the user has manually created an spapr-vty at address 0. So first we search for the specified reg and only if that doesn't match do we fall back. Signed-off-by: Michael Ellerman Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr_vty.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c index 815039501f..f23cc36231 100644 --- a/hw/spapr_vty.c +++ b/hw/spapr_vty.c @@ -69,6 +69,9 @@ static int spapr_vty_init(VIOsPAPRDevice *sdev) return 0; } +/* Forward declaration */ +static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg); + static target_ulong h_put_term_char(CPUState *env, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { @@ -76,9 +79,10 @@ static target_ulong h_put_term_char(CPUState *env, sPAPREnvironment *spapr, target_ulong len = args[1]; target_ulong char0_7 = args[2]; target_ulong char8_15 = args[3]; - VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg); + VIOsPAPRDevice *sdev; uint8_t buf[16]; + sdev = vty_lookup(spapr, reg); if (!sdev) { return H_PARAMETER; } @@ -102,9 +106,10 @@ static target_ulong h_get_term_char(CPUState *env, sPAPREnvironment *spapr, target_ulong *len = args + 0; target_ulong *char0_7 = args + 1; target_ulong *char8_15 = args + 2; - VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg); + VIOsPAPRDevice *sdev; uint8_t buf[16]; + sdev = vty_lookup(spapr, reg); if (!sdev) { return H_PARAMETER; } @@ -151,6 +156,29 @@ static VIOsPAPRDeviceInfo spapr_vty = { }, }; +static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg) +{ + VIOsPAPRDevice *sdev; + + sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg); + if (!sdev && reg == 0) { + DeviceState *qdev; + + /* Hack for kernel early debug, which always specifies reg==0. + * We search all VIO devices, and grab the first available vty + * device. This attempts to mimic existing PowerVM behaviour + * (early debug does work there, despite having no vty with + * reg==0. */ + QTAILQ_FOREACH(qdev, &spapr->vio_bus->bus.children, sibling) { + if (qdev->info == &spapr_vty.qdev) { + return DO_UPCAST(VIOsPAPRDevice, qdev, qdev); + } + } + } + + return sdev; +} + static void spapr_vty_register(void) { spapr_vio_bus_register_withprop(&spapr_vty); From 1e34d859d01a408dc8479b1858bb103aa3b4f9a7 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 15 Nov 2011 18:53:13 +0000 Subject: [PATCH 9/9] pseries: Fix qdev.id handling in the VIO bus code When the user creates a device on the command line with -device, they can specify the id, using id=foo. Currently the VIO bus code overwrites this id with it's own value. We should only set qdev.id if it is not already set by the user. The device tree code uses qdev.id for the device tree node name, however we can't rely on the user specifiying the id using proper device tree syntax, ie. device@reg. So separate the device tree node name from the qdev.id, but use the same syntax, so they will match by default. Signed-off-by: Michael Ellerman Signed-off-by: Alexander Graf --- hw/spapr_vio.c | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index b7b3ddd116..2dcc0361ed 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -73,20 +73,39 @@ VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg) return NULL; } +static char *vio_format_dev_name(VIOsPAPRDevice *dev) +{ + VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)dev->qdev.info; + char *name; + + /* Device tree style name device@reg */ + if (asprintf(&name, "%s@%x", info->dt_name, dev->reg) < 0) { + return NULL; + } + + return name; +} + #ifdef CONFIG_FDT static int vio_make_devnode(VIOsPAPRDevice *dev, void *fdt) { VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)dev->qdev.info; - int vdevice_off, node_off; - int ret; + int vdevice_off, node_off, ret; + char *dt_name; vdevice_off = fdt_path_offset(fdt, "/vdevice"); if (vdevice_off < 0) { return vdevice_off; } - node_off = fdt_add_subnode(fdt, vdevice_off, dev->qdev.id); + dt_name = vio_format_dev_name(dev); + if (!dt_name) { + return -ENOMEM; + } + + node_off = fdt_add_subnode(fdt, vdevice_off, dt_name); + free(dt_name); if (node_off < 0) { return node_off; } @@ -608,12 +627,15 @@ static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo) VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev; char *id; - if (asprintf(&id, "%s@%x", info->dt_name, dev->reg) < 0) { - return -1; + /* Don't overwrite ids assigned on the command line */ + if (!dev->qdev.id) { + id = vio_format_dev_name(dev); + if (!id) { + return -1; + } + dev->qdev.id = id; } - dev->qdev.id = id; - dev->qirq = spapr_allocate_irq(dev->vio_irq_num, &dev->vio_irq_num); if (!dev->qirq) { return -1;