From 986626efecae87af17a9d9726767501cb4687b8c Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 18 Nov 2011 16:41:59 +0100 Subject: console: Fix segfault on screendump without VGA adapter When trying to create a screen dump without having any VGA adapter inside the guest, QEMU segfaults. This is because it's trying to switch back to the "previous" screen it was on before dumping the VGA screen. Unfortunately, in my case there simply is no previous screen so it accesses a NULL pointer. Fix it by checking if previous_active_console is actually available. This is 1.0 material. Signed-off-by: Alexander Graf --- console.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/console.c b/console.c index f6fe44195..ed6a653fd 100644 --- a/console.c +++ b/console.c @@ -186,7 +186,9 @@ void vga_hw_screen_dump(const char *filename) consoles[0]->hw_screen_dump(consoles[0]->hw, filename); } - console_select(previous_active_console->index); + if (previous_active_console) { + console_select(previous_active_console->index); + } } void vga_hw_text_update(console_ch_t *chardata) -- cgit v1.2.3 From 57ee5f77c09d365d470cd208c76a7a01a85435b2 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 28 Nov 2011 20:21:39 +0000 Subject: pseries: Fix array overrun bug in PCI code spapr_populate_pci_devices() containd a loop with PCI_NUM_REGIONS (7) iterations. However this overruns the 'bars' global array, which only has 6 elements. In fact we only want to run this loop for things listed in the bars array, so this patch corrects the loop bounds to reflect that. Signed-off-by: David Gibson Signed-off-by: Alexander Graf (cherry picked from commit 135712de61dfa22368e98914d65b8b0860ec8505) --- hw/spapr_pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c index 716258854..9b6a032cc 100644 --- a/hw/spapr_pci.c +++ b/hw/spapr_pci.c @@ -454,7 +454,7 @@ int spapr_populate_pci_devices(sPAPRPHBState *phb, reg[0].size = 0; n = 0; - for (i = 0; i < PCI_NUM_REGIONS; ++i) { + for (i = 0; i < ARRAY_SIZE(bars); ++i) { if (0 == dev->io_regions[i].size) { continue; } -- cgit v1.2.3 From adf6c527b07b1399cae990d48fa7b87113bd5083 Mon Sep 17 00:00:00 2001 From: Liu Yu-B13201 Date: Mon, 28 Nov 2011 20:41:18 +0000 Subject: kvm-ppc: halt secondary cpus when guest reset When guest reset, we need to halt secondary cpus until guest kick them. This already works for tcg. The patch add the support for kvm. Signed-off-by: Liu Yu Signed-off-by: Alexander Graf [agraf: remove in-kernel irqchip code] (cherry picked from commit 157feeadbaec09fe4dca539a24f6f6d327d6eeb6) --- hw/ppce500_spin.c | 1 + target-ppc/kvm.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/ppce500_spin.c b/hw/ppce500_spin.c index cccd94073..2b527282b 100644 --- a/hw/ppce500_spin.c +++ b/hw/ppce500_spin.c @@ -112,6 +112,7 @@ static void spin_kick(void *data) env->halted = 0; env->exception_index = -1; + env->stopped = 0; qemu_cpu_kick(env); } diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 429349fb9..9b2e605b6 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -504,7 +504,7 @@ void kvm_arch_post_run(CPUState *env, struct kvm_run *run) int kvm_arch_process_async_events(CPUState *env) { - return 0; + return env->halted; } static int kvmppc_handle_halt(CPUState *env) -- cgit v1.2.3 From e295c31e25b044acba2a48f1e7292b9fbb896367 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 12 Dec 2011 18:24:32 +0000 Subject: pseries: Emit device tree nodes in reg order Although in theory the device tree has no inherent ordering, in practice the order of nodes in the device tree does effect the order that devices are detected by software. Currently the ordering is determined by the order the devices appear on the QEMU command line. Although that does give the user control over the ordering, it is fragile, especially when the user does not generate the command line manually - eg. when using libvirt etc. So order the device tree based on the reg value, ie. the address of on the VIO bus of the devices. This gives us a sane and stable ordering. Signed-off-by: Michael Ellerman Signed-off-by: David Gibson Signed-off-by: Alexander Graf [agraf] add braces (cherry picked from commit 05c194384f836240ea4c2da5fa3be43a54bff021) --- hw/spapr_vio.c | 50 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index 2dcc0361e..8bd00cade 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -749,21 +749,61 @@ static void spapr_vio_register_devices(void) device_init(spapr_vio_register_devices) #ifdef CONFIG_FDT +static int compare_reg(const void *p1, const void *p2) +{ + VIOsPAPRDevice const *dev1, *dev2; + + dev1 = (VIOsPAPRDevice *)*(DeviceState **)p1; + dev2 = (VIOsPAPRDevice *)*(DeviceState **)p2; + + if (dev1->reg < dev2->reg) { + return -1; + } + if (dev1->reg == dev2->reg) { + return 0; + } + + /* dev1->reg > dev2->reg */ + return 1; +} + int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt) { - DeviceState *qdev; - int ret = 0; + DeviceState *qdev, **qdevs; + int i, num, ret = 0; + /* Count qdevs on the bus list */ + num = 0; QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) { - VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev; + num++; + } + + /* Copy out into an array of pointers */ + qdevs = g_malloc(sizeof(qdev) * num); + num = 0; + QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) { + qdevs[num++] = qdev; + } + + /* Sort the array */ + qsort(qdevs, num, sizeof(qdev), compare_reg); + + /* Hack alert. Give the devices to libfdt in reverse order, we happen + * to know that will mean they are in forward order in the tree. */ + for (i = num - 1; i >= 0; i--) { + VIOsPAPRDevice *dev = (VIOsPAPRDevice *)(qdevs[i]); ret = vio_make_devnode(dev, fdt); if (ret < 0) { - return ret; + goto out; } } - return 0; + ret = 0; +out: + free(qdevs); + + return ret; } #endif /* CONFIG_FDT */ -- cgit v1.2.3 From 447a3b347381162f9c2b1b7831643b6ee0e767ca Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 12 Dec 2011 18:24:33 +0000 Subject: pseries: Add a routine to find a stable "default" vty and use it In vty_lookup() we have a special case for supporting early debug in the kernel. This accepts reg == 0 as a special case to mean "any vty". We implement this by searching the vtys on the bus and returning the first we find. This means that the vty we chose depends on the order the vtys are specified on the QEMU command line - because that determines the order of the vtys on the bus. We'd rather the command line order was irrelevant, so instead return the vty with the lowest reg value. This is still a guess as to what the user really means, but it is at least stable WRT command line ordering. Signed-off-by: Michael Ellerman Signed-off-by: David Gibson Signed-off-by: Alexander Graf [agraf] fix braces (cherry picked from commit 98331f8ad6a3e2cfbb402d72e6be47eac7706251) --- hw/spapr_vty.c | 47 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c index f23cc3623..e2fec5880 100644 --- a/hw/spapr_vty.c +++ b/hw/spapr_vty.c @@ -156,24 +156,53 @@ static VIOsPAPRDeviceInfo spapr_vty = { }, }; +static VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus) +{ + VIOsPAPRDevice *sdev, *selected; + DeviceState *iter; + + /* + * To avoid the console bouncing around we want one VTY to be + * the "default". We haven't really got anything to go on, so + * arbitrarily choose the one with the lowest reg value. + */ + + selected = NULL; + QTAILQ_FOREACH(iter, &bus->bus.children, sibling) { + /* Only look at VTY devices */ + if (iter->info != &spapr_vty.qdev) { + continue; + } + + sdev = DO_UPCAST(VIOsPAPRDevice, qdev, iter); + + /* First VTY we've found, so it is selected for now */ + if (!selected) { + selected = sdev; + continue; + } + + /* Choose VTY with lowest reg value */ + if (sdev->reg < selected->reg) { + selected = sdev; + } + } + + return selected; +} + 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 + * We search all VIO devices, and grab the vty with the lowest + * reg. 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 spapr_vty_get_default(spapr->vio_bus); } return sdev; -- cgit v1.2.3 From 7a6d80e93cb461a985ffb64bc4d19dd5f726386b Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 13 Dec 2011 15:24:34 +1100 Subject: pseries: Populate "/chosen/linux,stdout-path" in the FDT There is a device tree property "/chosen/linux,stdout-path" which indicates which device should be used as stdout - ie. "the console". Currently we don't specify anything, which means both firmware and Linux choose something arbitrarily. Use the routine we added in the last patch to pick a default vty and specify it as stdout. Currently SLOF doesn't use the property, but we are hoping to update it to do so. Signed-off-by: Michael Ellerman Signed-off-by: David Gibson Signed-off-by: Alexander Graf (cherry picked from commit 68f3a94c64bbaaf8c7f2daa70de1b5d87a432f86) --- hw/spapr.c | 2 ++ hw/spapr_vio.c | 34 ++++++++++++++++++++++++++++++++++ hw/spapr_vio.h | 3 +++ hw/spapr_vty.c | 2 +- 4 files changed, 40 insertions(+), 1 deletion(-) diff --git a/hw/spapr.c b/hw/spapr.c index 2b901f105..5a98d8651 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -351,6 +351,8 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr, fprintf(stderr, "Couldn't set up RTAS device tree properties\n"); } + spapr_populate_chosen_stdout(fdt, spapr->vio_bus); + _FDT((fdt_pack(fdt))); cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt)); diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index 8bd00cade..464fe8744 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -806,4 +806,38 @@ out: return ret; } + +int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus) +{ + VIOsPAPRDevice *dev; + char *name, *path; + int ret, offset; + + dev = spapr_vty_get_default(bus); + if (!dev) + return 0; + + offset = fdt_path_offset(fdt, "/chosen"); + if (offset < 0) { + return offset; + } + + name = vio_format_dev_name(dev); + if (!name) { + return -ENOMEM; + } + + if (asprintf(&path, "/vdevice/%s", name) < 0) { + path = NULL; + ret = -ENOMEM; + goto out; + } + + ret = fdt_setprop_string(fdt, offset, "linux,stdout-path", path); +out: + free(name); + free(path); + + return ret; +} #endif /* CONFIG_FDT */ diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h index a325a5f4b..9fcd304ad 100644 --- a/hw/spapr_vio.h +++ b/hw/spapr_vio.h @@ -83,6 +83,7 @@ extern VIOsPAPRBus *spapr_vio_bus_init(void); extern VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg); extern void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info); extern int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt); +extern int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus); extern int spapr_vio_signal(VIOsPAPRDevice *dev, target_ulong mode); @@ -108,6 +109,8 @@ void spapr_vty_create(VIOsPAPRBus *bus, uint32_t reg, CharDriverState *chardev); void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd); void spapr_vscsi_create(VIOsPAPRBus *bus, uint32_t reg); +VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus); + int spapr_tce_set_bypass(uint32_t unit, uint32_t enable); void spapr_vio_quiesce(void); diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c index e2fec5880..386ccf720 100644 --- a/hw/spapr_vty.c +++ b/hw/spapr_vty.c @@ -156,7 +156,7 @@ static VIOsPAPRDeviceInfo spapr_vty = { }, }; -static VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus) +VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus) { VIOsPAPRDevice *sdev, *selected; DeviceState *iter; -- cgit v1.2.3 From d928541b51731a185214924cc5b44cd28020fa4f Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 11 Jan 2012 19:46:27 +0000 Subject: pseries: Don't try to munmap() a malloc()ed TCE table For the pseries machine, TCE (IOMMU) tables can either be directly malloc()ed in qemu or, when running on a KVM which supports it, mmap()ed from a KVM ioctl. The latter option is used when available, because it allows the (frequent bottlenext) H_PUT_TCE hypercall to be KVM accelerated. However, even when KVM is persent, TCE acceleration is not always possible. Only KVM HV supports this ioctl(), not KVM PR, or the kernel could run out of contiguous memory to allocate the new table. In this case we need to fall back on the malloc()ed table. When a device is removed, and we need to remove the TCE table, we need to either munmap() or free() the table as appropriate for how it was allocated. The code is supposed to do that, but we buggily fail to initialize the tcet->fd variable in the malloc() case, which is used as a flag to determine which is the right choice. This patch fixes the bug, and cleans up error messages relating to this path while we're at it. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/kvm.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 9b2e605b6..0410901b5 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -838,12 +838,18 @@ void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd) int fd; void *table; + /* Must set fd to -1 so we don't try to munmap when called for + * destroying the table, which the upper layers -will- do + */ + *pfd = -1; if (!cap_spapr_tce) { return NULL; } fd = kvm_vm_ioctl(kvm_state, KVM_CREATE_SPAPR_TCE, &args); if (fd < 0) { + fprintf(stderr, "KVM: Failed to create TCE table for liobn 0x%x\n", + liobn); return NULL; } @@ -852,6 +858,8 @@ void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd) table = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (table == MAP_FAILED) { + fprintf(stderr, "KVM: Failed to map TCE table for liobn 0x%x\n", + liobn); close(fd); return NULL; } @@ -871,8 +879,8 @@ int kvmppc_remove_spapr_tce(void *table, int fd, uint32_t window_size) len = (window_size / SPAPR_VIO_TCE_PAGE_SIZE)*sizeof(VIOsPAPR_RTCE); if ((munmap(table, len) < 0) || (close(fd) < 0)) { - fprintf(stderr, "KVM: Unexpected error removing KVM SPAPR TCE " - "table: %s", strerror(errno)); + fprintf(stderr, "KVM: Unexpected error removing TCE table: %s", + strerror(errno)); /* Leak the table */ } -- cgit v1.2.3